Spring-bean的生命周期

初始化和销毁回调

在bean交由spring管理的过程中,bean从初始化到销毁之间经历许多过程,其中初始化回调方法会在bean实例化之后,属性赋值(set方法执行)之前被调用;销毁回调方法会在bean即将被销毁之前调用,可以在销毁回调中做一些资源的释放工作。

InitializingBean和DisposableBean接口

public interface InitializingBean {
	//属性初始化之前被调用
	void afterPropertiesSet() throws Exception;

}
public interface DisposableBean {
	//销毁bean之前被调用
	void destroy() throws Exception;

}

实现InitializingBean的bean,会在属性初始化之前被调用,实现DisposableBean的bean,会在bean即将被销毁时调用。

演示

@Component
public class InitAndDestroyBean implements InitializingBean, DisposableBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitAndDestroyBean初始化...");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("InitAndDestroyBean销毁...");
    }
}
@Configuration
@ComponentScan("com.vm")
public class SpringConfig {

}
public class InitAndDestroyBeanTest {
    public static ApplicationContext app;
    @BeforeClass
    public static void before(){
        app = new AnnotationConfigApplicationContext(SpringConfig.class);
    }
    @AfterClass
    public static void after(){
        if (app instanceof AbstractApplicationContext)
            ((AbstractApplicationContext)app).close();//关闭容器
    }

    @Test
    public void test(){
        InitAndDestroyBean bean = app.getBean(InitAndDestroyBean.class);
        System.out.println(bean);
    }
}

在这里插入图片描述

@PostConstruct和@PreDestroy注解

@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}

被@PostConstruct标注的方法将会被当初初始化回调,被@PreDestroy标注的方法将会被作为销毁回调执行。

演示

@Component
public class InitAndDestroyBean2 {
    @PostConstruct
    public void initMethod(){
        System.out.println("InitAndDestroyBean2初始化...");
    }

    @PreDestroy
    public void destoryMethod(){
        System.out.println("InitAndDestroyBean2销毁...");
    }
}
public class InitAndDestroyBeanTest {
    public static ApplicationContext app;
    @BeforeClass
    public static void before(){
        app = new AnnotationConfigApplicationContext(SpringConfig.class);
    }
    @AfterClass
    public static void after(){
        if (app instanceof AbstractApplicationContext)
            ((AbstractApplicationContext)app).close();//关闭容器
    }

    @Test
    public void test(){
        InitAndDestroyBean2 bean = app.getBean(InitAndDestroyBean2.class);
        System.out.println(bean);
    }
}

在这里插入图片描述

手动配置初始化和销毁回调

使用java配置类或xml配置一个bean到容器时,可以为这个bean指定初始化和调回的回调方法。如下:

public class InitAndDestroyBean3 {
    public void initMethod(){
        System.out.println("InitAndDestroyBean3初始化...");
    }

    public void destoryMethod(){
        System.out.println("InitAndDestroyBean3销毁...");
    }
}

使用Java配置类注入容器,配置如下

@Configuration
@ComponentScan("com.vm")
public class SpringConfig {

    @Bean(initMethod = "initMethod",destroyMethod = "destoryMethod")
    public InitAndDestroyBean3 getInitAndDestroyBean3(){
        return new InitAndDestroyBean3();
    }
}

initMethod 属性指定一个初始化回调的方法名,destroyMethod 指定一个销毁回调方法。XML同等配置如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.vm"/>

    <bean id="initAndDestroyBean3" class="com.vm.pojo.InitAndDestroyBean3" init-method="initMethod" destroy-method="destoryMethod"/>

</beans>

演示

public class InitAndDestroyBeanTest {
    public static ApplicationContext app;
    @BeforeClass
    public static void before(){
        app = new AnnotationConfigApplicationContext(SpringConfig.class);
    }
    @AfterClass
    public static void after(){
        if (app instanceof AbstractApplicationContext)
            ((AbstractApplicationContext)app).close();//关闭容器
    }

    @Test
    public void test(){
        InitAndDestroyBean3 bean = app.getBean(InitAndDestroyBean3.class);
        System.out.println(bean);
    }
}

在这里插入图片描述

执行顺序

如果一个bean同时使用上述三种方式配置,他的执行顺序如下:

注解->接口->配置

演示

public class InitAndDestroyBean4 implements InitializingBean, DisposableBean {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("接口初始化...");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("接口销毁...");
    }
    @PostConstruct
    public void initMethod(){
        System.out.println("注解初始化...");
    }

    @PreDestroy
    public void destoryMethod(){
        System.out.println("注解销毁...");
    }

    public void initMethod2(){
        System.out.println("配置初始化...");
    }

    public void destoryMethod2(){
        System.out.println("配置销毁...");
    }
}

@Configuration
@ComponentScan("com.vm")
public class SpringConfig {
    @Bean(initMethod = "initMethod2",destroyMethod = "destoryMethod2")
    public InitAndDestroyBean4 getInitAndDestroyBean4(){
        return new InitAndDestroyBean4();
    }
}
public class InitAndDestroyBeanTest {
    public static ApplicationContext app;
    @BeforeClass
    public static void before(){
        app = new AnnotationConfigApplicationContext(SpringConfig.class);
    }
    @AfterClass
    public static void after(){
        if (app instanceof AbstractApplicationContext)
            ((AbstractApplicationContext)app).close();//关闭容器
    }

    @Test
    public void test(){
        InitAndDestroyBean4 bean = app.getBean(InitAndDestroyBean4.class);
        System.out.println(bean);
    }
}

在这里插入图片描述

容器的启动和关闭

在容器的启动或关闭阶段,bean实现了相应的接口,可以被通知到(调用回调方法)

Lifecycle接口

public interface Lifecycle {
    void start();

    void stop();

    boolean isRunning();
}

start()方法在容器启动时被调用;stop()在容器被关闭时调用;isRunning()用来判断容器是否在运行;当isRunning()返回false时start()方法才能被执行,同理当isRunning()返回true时stop()方法才能被执行。

演示

@Component
public class LifecycleImpl implements Lifecycle {
    private boolean isRunning = false;
    @Override
    public void start() {
        System.out.println("LifecycleImpl.start...");
        isRunning = true;
    }

    @Override
    public void stop() {
        System.out.println("LifecycleImpl.stop...");
        isRunning = false;
    }

    @Override
    public boolean isRunning() {
        return isRunning;
    }
}
public class LifecycleTest {
    public static ApplicationContext app;
    @BeforeClass
    public static void before(){
        app = new AnnotationConfigApplicationContext(SpringConfig.class);
        if (app instanceof AbstractApplicationContext)
            ((AbstractApplicationContext)app).start();

    }
    @AfterClass
    public static void after(){
        if (app instanceof AbstractApplicationContext)
            ((AbstractApplicationContext)app).close();
    }

    @Test
    public void test(){
        LifecycleImpl bean = app.getBean(LifecycleImpl.class);
        System.out.println(bean);
    }
}

在这里插入图片描述
需要注意,start()和stop()方法要想被调用,必须手动调用容器的start()和close()方法,这是不智能的,大部分情况下我们希望这些方法能被自动调用。

SmartLifecycle接口

public interface SmartLifecycle extends Lifecycle, Phased {
    int DEFAULT_PHASE = 2147483647;

	/**
	*是否自动启动,当返回值为true,SmartLifecycle 的start()方法将会在容器启动时被调用,而不需要再去手动的调用容器的启动方法,反之则和Lifecycle接口类似
	*/
    default boolean isAutoStartup() {
        return true;
    }

	/**
	*该方法会在容器关闭时被调用,入参callback一定要执行一下,相当于告诉容器stop()方法逻辑执行完毕,这个接口的默认实现调用了父接口Lifecycle的stop()方法,所以实际的逻辑也可以写在stop()方法,或者重写该方法,但是别忘记执行callback.run()
	*/
    default void stop(Runnable callback) {
        this.stop();
        callback.run();
    }

	/**
	*用于确定执行顺序
	*/
    default int getPhase() {
        return 2147483647;
    }
}

public interface Phased {
    int getPhase();
}

SmartLifecycle继承了Lifecycle接口,同时还继承了Phased ,Phased 接口的作用是当我们同时向容器中注入多个SmartLifecycle类型的bean时,能指定它们的执行顺序,数值越小,优先级越高。

演示

@Component
public class SmartLifecycleImpl implements SmartLifecycle {
    private boolean isRunning = false;

    @Override
    public void start() {
        System.out.println("SmartLifecycleImpl.start...");
        isRunning = true;
    }

    @Override
    public void stop() {
        System.out.println("SmartLifecycleImpl.stop...");
        isRunning = false;
    }

    @Override
    public boolean isRunning() {
        return isRunning;
    }

    @Override
    public int getPhase() {
        return 1;
    }
}

@Component
public class SmartLifecycleImpl2 implements SmartLifecycle {
    private boolean isRunning = false;

    @Override
    public void start() {
        System.out.println("SmartLifecycleImpl2.start...");
        isRunning = true;
    }

    @Override
    public void stop() {
        System.out.println("SmartLifecycleImpl2.stop...");
        isRunning = false;
    }

    @Override
    public boolean isRunning() {
        return isRunning;
    }

    @Override
    public int getPhase() {
        return 2;
    }
}
public class LifecycleTest {
    public static ApplicationContext app;
    @BeforeClass
    public static void before(){
        app = new AnnotationConfigApplicationContext(SpringConfig.class);
        if (app instanceof AbstractApplicationContext)
            ((AbstractApplicationContext)app).registerShutdownHook();//向JVM注册一个关闭钩子函数,程序执行完毕由JVM关闭容器,无需我们调用容器的close()方法

    }

    @Test
    public void testSmartLifecycleImpl(){
        SmartLifecycleImpl bean1 = app.getBean(SmartLifecycleImpl.class);
        SmartLifecycleImpl2 bean2 = app.getBean(SmartLifecycleImpl2.class);
        System.out.println(bean1);
        System.out.println(bean2);
    }
}

在这里插入图片描述
方法被正确的调用,并且执行顺序也正确。

LifecycleProcessor接口

public interface LifecycleProcessor extends Lifecycle {
	/**
	*容器刷新时被调用
	*/
    void onRefresh();
    
	/**
	*容器关闭时被调用
	*/
    void onClose();
}

LifecycleProcessor也继承了Lifecycle 接口,同时还扩展了两个方法。
这个接口是一个很重要的接口,SmartLifecycle和Lifecycle 接口都依赖于spring提供的一个LifecycleProcessor的默认实现类DefaultLifecycleProcessor。
SmartLifecycle和Lifecycle被调用的逻辑实际在DefaultLifecycleProcessor中,AbstractApplicationContext的部分源码如下:
在这里插入图片描述

在这里插入图片描述
从第二张图可以看出,如果我们需要向容器中注入一个自定义的LifecycleProcessor实现类替换默认的DefaultLifecycleProcessor,那么bean的名字必须叫“lifecycleProcessor”,否则只能被当作一个普通的Lifecycle 接口的实现类了。
需要注意的时,如果我们替换了默认的DefaultLifecycleProcessor,那么实现SmartLifecycle和Lifecycle的接口的bean可能不会被调用了,除非我们自定义的LifecycleProcessor实现类有类似DefaultLifecycleProcessor的逻辑。

演示

@Component("lifecycleProcessor")
public class LifecycleProcessorImpl implements LifecycleProcessor {
    private boolean isRunning = false;

    @Override
    public void onRefresh() {
        System.out.println("LifecycleProcessorImpl.onRefresh...");
        isRunning = true;
    }

    @Override
    public void onClose() {
        System.out.println("LifecycleProcessorImpl.onClose...");
        isRunning = false;
    }

    @Override
    public void start() {
        System.out.println("LifecycleProcessorImpl.start...");
        isRunning = true;
    }

    @Override
    public void stop() {
        System.out.println("LifecycleProcessorImpl.stop...");
        isRunning = false;
    }

    @Override
    public boolean isRunning() {
        return isRunning;
    }
}
public class LifecycleTest {
    public static ApplicationContext app;
    @BeforeClass
    public static void before(){
        app = new AnnotationConfigApplicationContext(SpringConfig.class);
        if (app instanceof AbstractApplicationContext)
            ((AbstractApplicationContext)app).registerShutdownHook();//向JVM注册一个关闭钩子函数,程序执行完毕由JVM关闭容器,无需我们调用容器的close()方法

    }

    @Test
    public void testLifecycleProcessorImpl(){
        LifecycleProcessorImpl bean = app.getBean(LifecycleProcessorImpl.class);
        System.out.println(bean);
    }
}

在这里插入图片描述
onRefresh()方法会在容器刷新时被执行,onClose()方法会在容器关闭时被执行。start()和stop()方法需要手动调用容器的start()和stop()方法时才会被调用。

  • 25
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值