zoukankan      html  css  js  c++  java
  • 四、Srping之Bean的初始化和销毁

    Srping之Bean的初始化和销毁方法

    通常,bean的初始化和销毁方法我们有三个地方可以入手,分别是:

    • 自定义初始化,销毁方法
    • 实现spring提供的InitializingBean(初始化逻辑),DisposableBean(销毁逻辑)接口
    • JSR250;@PostConstruct,@PreDestroy执行初始化和销毁方法
    • 实现spring提供的BeanPostProcessor接口,实现其postProcessBeforeInitialization方法来执行在初始化之前的操作,实现postProcessAfterInitialization方法来执行初始化之后的操作。

    bean的生命周期:实例化 -> 属性赋值 -> 初始化 -> 销毁

    【1】自定义初始化,销毁方法

    ​ 容器管理bean的生命周期:我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法

    构造(对象创建):

    • 单实例:在容器启动的时候创建对象
    • 多实例:在每次获取的时候创建对象

    销毁:

    • 单实例:容器关闭的时候
    • 多实例:容器不会管理这个bean;容器不会调用销毁方法,如果需要,自己手动调用销毁方法。

    ​ 定义一个Person类,然后定义两个方法,一个是我们想作为初始化方法的init方法,一个是我们想作为销毁方法的destory方法

    public class Person {
        public Person() {
            System.out.println("Person...constructor");
        }
    
        public void init(){
            System.out.println("Person...init");
        }
    
        public void destroy(){
            System.out.println("Person...destroy");
        }
    }
    

    ​ 将Person添加到配置类当中

    @Configuration
    public class LifeCycleConfig {
    
        @Bean(initMethod = "init",destroyMethod = "destroy")
        public Person person(){
            return new Person();
        }
    }
    

    ​ 测试结果

    public class LifeCycleConfigTest {
        @Test
        public void testLifeCycle(){
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
            System.out.println("容器创建完成了...");
            applicationContext.close();
        }
    }
    /**
    Person...constructor
    Person...init
    容器创建完成了...
    Person...destroy
    */
    

    【2】InitializingBean和DisposableBean接口

    ​ 我们还是在之前的Person类代码上继续编写

    public class Person implements InitializingBean,DisposableBean{
        public Person() {
            System.out.println("Person...constructor");
        }
    
        public void init(){
            System.out.println("Person...init");
        }
    
        public void destry(){
            System.out.println("Person...destroy");
        }
        /**
         * 当beanFactory关闭且bean为单例的对象时触发
         * @throws Exception
         */
        @Override
        public void destroy() throws Exception {
            System.out.println("DisposableBean...Person.....destroy....");
        }
    
        /**
         * 当beanFactory实例化bean后,将所有的属性值设置完毕之后,才会调用该接口方法。
         * @throws Exception
         */
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("InitializingBean...Person.....afterPropertiesSet....");
        }
    }
    

    ​ 测试结果

    /**
    Person...constructor
    InitializingBean...Person.....afterPropertiesSet....
    Person...init
    容器创建完成了...
    DisposableBean...Person.....destroy....
    Person...destroy
    */
    

    可以看到,

    • 初始化过程:容器先调用了Person的无参构造方法来实例化Person对象实例,接着执行了InitialiaingBean的初始化方法afterPropertiesSet()方法,最后才执行我们自定义的init初始化方法。
    • 销毁过程:同样,容器也是先执行了DisposableBean的destroy方法,然后才执行了我们自定义的destry销毁方法。

    【3】JSR250:@PostConstruct,@PreDestroy

    • @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法,
    • @PreDestroy:在容器销毁bean之前通知我们进行清理工作

    ​ 继续在上面的Person代码上修改

    public class Person implements InitializingBean,DisposableBean{
        public Person() {
            System.out.println("Person...constructor");
        }
    
        public void init(){
            System.out.println("Person...init");
        }
    
        public void destry(){
            System.out.println("Person...destroy");
        }
    
        @PostConstruct
        public void PostConstruct() {
            System.out.println("JSR250....PostConstruct....Person ... PostConstruct...");
        }
    
        @PreDestroy
        public void PreDestroy() {
            System.out.println("JSR250....PreDestroy....Person ... PreDestroy...");
        }
    
        /**
         * 当beanFactory关闭且bean为单例的对象时触发
         * @throws Exception
         */
        @Override
        public void destroy() throws Exception {
            System.out.println("DisposableBean...Person.....destroy....");
        }
    
        /**
         * 当beanFactory实例化bean后,将所有的属性值设置完毕之后,才会调用该接口方法。
         * @throws Exception
         */
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("InitializingBean...Person.....afterPropertiesSet....");
        }
    }
    

    ​ 测试结果:

    /**
    Person...constructor
    JSR250....PostConstruct....Person ... PostConstruct...
    InitializingBean...Person.....afterPropertiesSet....
    Person...init
    容器创建完成了...
    JSR250....PreDestroy....Person ... PreDestroy...
    DisposableBean...Person.....destroy....
    Person...destroy
    */
    

    可以看到:

    • 初始化方法的执行顺序:先执行Toyota的无参构造方法,再执行JSR250的PostConstruct初始化方法,接着执行InitializingBean的afterPropertiesSet初始化方法,最后执行我们自定义的init初始化方法。
    • 销毁方法的执行顺序:和初始化方法一样,先执行JSR250的PerDestroy销毁方法,再执行DisposableBean的destroy方法,最后执行我们自定义的destry销毁方法。

    【4】实现BeanPostProcessor接口

    ​ BeanPostProcessor是bean的后置处理器,在bean初始化前后进行一些处理工作:

    • postProcessBeforeInitialization:在初始化之前工作

    • postProcessAfterInitialization:在初始化之后工作

      直接观察代码,会发现BeanPostProcessor的方法postProcessBeforeInitialization有返回类型Object,

    postProcessAfterInitialization也有返回类型Object,同时两个方法都可以抛出BeansException异常。

    ​ 首先定义一个我们自己的BeanPostProcessor:

    @Component
    public class LifeCycleBeanPostProcessor implements BeanPostProcessor {
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		if (bean instanceof Person) {
    			System.err.println("postProcessBeforeInitialization....拦截指定bean");
    		}
    		System.out.println("这句话证明所有容器中的bean都会被postProcessBeforeInitialization拦截.. beanName=" + beanName + "==>" + bean);
    		return bean;
    	}
     
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		if (bean instanceof Person) {
    			System.err.println("postProcessAfterInitialization.....拦截指定bean");
    		}
    		System.out.println("这句话证明所有容器中的bean都会被postProcessAfterInitialization拦截.. beanName=" + beanName + "==>" + bean);
    		return bean;
    	}
    }
    

    ​ 接着在配置类中添加注解包扫描:

    @Configuration
    @ComponentScan("com.zl")
    public class LifeCycleConfig {
    
        @Bean(initMethod = "init",destroyMethod = "destry")
        public Person person(){
            return new Person();
        }
    }
    

    ​ 测试结果:

    第一个标示点:说明所有容器加载的bean在实例化之后,初始化之前都会执行postProcessBeforeInitialization方法,在初始化完成后执行postProcessAfterInitialization方法。

    第二个标示点:说明我们可以只拦截我们指定的bean,并且执行的顺序是:

    • 1.容器对bean进行实例化
    • 2.初始化前执行自定义BeanPostProcessor的postProcessBeforeInitialization方法
    • 3.如果存在JSR250的初始化方法,则执行其初始化方法
    • 4.如果实现了InitializingBean接口,则执行其afterPropertiesSet方法
    • 5.如果存在我们自定义的初始化方法(initMethod),则执行自定义初始化方法
    • 6.初始化方法结束后,执行自定义BeanPostProcessor的postProcessAfterInitialization方法。
    • 7.容器关闭时,若存在JSR250的销毁方法,则先调用JSR250的销毁方法
    • 8.若实现了DisposableBean接口,则调用其destroy方法
    • 9.最后,若存在我们自定义的销毁方法(destroyMethod),则执行我们自定义的销毁方法

    以上九点,按顺序执行,完成bean的初始化和销毁工作。

    需要注意的是,BeanPostProcessor提供的两个方法,是针对初始化前后的拦截操作,和容器的关闭,bean的销毁无关。

  • 相关阅读:
    简单canvas五子棋
    javascript高级程序第三版学习笔记【执行环境、作用域】
    Error对象
    表单元素input、按钮、文字完美垂直居中对齐方法
    Firebug控制台详解
    JavaScript,JScript,ECMAScript及对应浏览器的版本
    valueOf和toString
    javascript高级程序第三版学习笔记【基本类型和引用类型】
    图的实现(邻接链表C#)
    基本排序算法(C)
  • 原文地址:https://www.cnblogs.com/lee0527/p/11748299.html
Copyright © 2011-2022 走看看