当前位置 博文首页 > blackball1998的博客:Bean生命周期

    blackball1998的博客:Bean生命周期

    作者:[db:作者] 时间:2021-06-20 12:09

    Bean生命周期

    有时候我们需要在Bean构造过程中的各个时机,执行一些增强逻辑,这时候Spring为我们提供了多种灵活的构造时的增强方式,这些增强方式组成了Bean生命周期的一部分

    在这里插入图片描述

    指定初始化和销毁方法

    initMethod

    在指定一个Bean时,我们可以绑定一个initMethod,Spring在完成这个Bean的实例化之后,会调用绑定的initMethod

    @Data
    public class Person {
    
        private int age;
        private String name;
    
        public Person(int age, String name) {
            System.out.println("执行构造器");
            this.age = age;
            this.name = name;
        }
    
        public void doInit() {
            System.out.println("执行初始化方法");
        }
    
    }
    

    设置@BeaninitMethod属性为初始化方法的方法名

    @Configuration
    public class MyConfiguration {
    
        @Bean(initMethod = "doInit")
        public Person person() {
            return new Person(18, "wang");
        }
    
    }
    

    在这里插入图片描述

    可以看到Spring在执行完构造器之后调用了绑定的doInit方法

    destroyMethod

    destroyMethod的使用方法和initMethod是一样的,一个是初始化时调用,一个是销毁时调用

    @Data
    public class Person {
    
        private int age;
        private String name;
    
        public Person(int age, String name) {
            System.out.println("执行构造器");
            this.age = age;
            this.name = name;
        }
    
        public void doDestroy() {
            System.out.println("执行销毁方法");
        }
    
    }
    
    @Configuration
    public class MyConfiguration {
    
        @Bean(destroyMethod = "doDestroy")
        public Person person() {
            return new Person(18, "wang");
        }
    
    }
    

    在这里插入图片描述

    在测试方法结束时,Spring的IOC容器会关闭,当容器关闭时或当我们使用BeanDefinitionRegistryPostProcessor接口移除一个Bean时,将会调用绑定的销毁方法

    实现初始化和销毁接口

    InitializingBean

    Spring提供了一个InitializingBean接口,我们可以在定义Bean时实现这个接口,并重写afterPropertiesSet方法

    @Data
    public class Person implements InitializingBean {
    
        private int age;
        private String name;
    
        public Person(int age, String name) {
            System.out.println("执行构造器");
            this.age = age;
            this.name = name;
        }
    
        @Override
        public void afterPropertiesSet() {
            System.out.println("执行afterPropertiesSet");
        }
    }
    

    测试结果如下

    在这里插入图片描述

    效果跟initMethod也是一样的,在Bean完成实例化之后执行

    DisposableBean

    有用于初始化的接口,就有用于销毁的接口,可以看到这些Spring提供的方式都是成对出现的

    在定义Bean时实现DisposableBean接口,并重写destroy方法,可以在Bean销毁的时候调用

    @Data
    public class Person implements DisposableBean {
    
        private int age;
        private String name;
    
        public Person(int age, String name) {
            System.out.println("执行构造器");
            this.age = age;
            this.name = name;
        }
    
        @Override
        public void destroy() {
            System.out.println("执行destroy");
        }
    }
    

    在这里插入图片描述

    使用Java原生注解

    除了Spring之外,Java也提供了两个注解@PostConstruct和,Spring底层对这两个注解进行了处理

    @PostConstruct

    我们只需要在Bean中的方法上标注@PostConstruct注解,这个方法将会在Bean构造完成之后执行

    @Data
    public class Person {
    
        private int age;
        private String name;
    
        public Person(int age, String name) {
            System.out.println("执行构造器");
            this.age = age;
            this.name = name;
        }
    
        @PostConstruct
        public void doPostConstruct() {
            System.out.println("执行PostConstruct");
        }
    }
    

    在这里插入图片描述

    @PreDestroy

    @PreDestroy的使用方式跟@PostConstruct一样,只需要标注在需要在Bean销毁时执行的方法上即可

    @Data
    public class Person {
    
        private int age;
        private String name;
    
        public Person(int age, String name) {
            System.out.println("执行构造器");
            this.age = age;
            this.name = name;
        }
    
        @PreDestroy
        public void doPerDestroy(){
            System.out.println("执行PerDestroy");
        }
    }
    

    在这里插入图片描述

    使用后置处理器

    除了以上方式外,Spring还提供了一个后置处理器来增强Bean的初始化,我们可以通过实现BeanPostProcessor接口来编写我们自定义的后置处理器

    @Component
    public class MyBeanProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("postProcessBeforeInitialization->" + bean);
            System.out.println("postProcessBeforeInitialization->" + beanName);
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("postProcessAfterInitialization->" + bean);
            System.out.println("postProcessAfterInitialization->" + beanName);
            return bean;
        }
    }
    

    创建一个自定义的组件类,实现BeanPostProcessor接口,并重写postProcessBeforeInitializationpostProcessAfterInitialization方法,这两个方法分别会在Bean的初始化之前和之后执行

    注意组件类需要添加@Component注解,这样组件类才会添加到IOC容器中被Spring获取到来执行

    postProcessBeforeInitializationpostProcessAfterInitialization方法中,参数列表的bean即为处理的bean对象,beanName为bean的名称。方法返回一个Object对象,我们可以拿到传入的bean对象,返回原来的bean对象,或者对bean进行一些处理,返回处理之后的bean

    后置处理器和前面的方式的区别是,他会对每一个Bean都生效,Spring在初始化每一个Bean时,会在IOC容器中寻找每一个后置处理器,包括Spring自带的和我们自定义的,遍历这些处理器执行其中的逻辑

    我们在测试中将initMethod也添加上,方便测试后置处理器中两个方法的执行时机

    测试结果如下

    在这里插入图片描述

    可以看到后置处理器确实对每一个Bean都进行了处理,除了我们自己添加的Person对象,还有好多Spring自带的Bean。

    Spring会在我们执行初始化方法之前执行postProcessBeforeInitialization方法,之后执行postProcessAfterInitialization方法。

    另外如果需要增强Bean的构造过程,可以使用InstantiationAwareBeanPostProcessor这个接口,使用方法大同小异

    执行顺序

    现在我们把每一种方式都用上,测试他们的执行顺序

    Bean的定义

    @Data
    public class Person implements InitializingBean, DisposableBean {
    
        private int age;
        private String name;
    
        public Person(int age, String name) {
            System.out.println("执行构造器");
            this.age = age;
            this.name = name;
        }
    
        public void doInit() {
            System.out.println("执行初始化方法");
        }
    
        public void doDestroy() {
            System.out.println("执行销毁方法");
        }
    
        @Override
        public void afterPropertiesSet() {
            System.out.println("执行afterPropertiesSet");
        }
    
        @Override
        public void destroy() {
            System.out.println("执行destroy");
        }
    
        @PostConstruct
        public void doPostConstruct() {
            System.out.println("执行PostConstruct");
        }
    
        @PreDestroy
        public void doPerDestroy() {
            System.out.println("执行PerDestroy");
        }
    
    }
    

    后置处理器

    @Component
    public class MyBeanProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof Person