Administrator
发布于 2022-12-09 / 42 阅读
0
0

Spring注解驱动---Bean生命周期

bean生命周期

bean生命周期指的是bean组件从创建到销毁的过程;bean生命周期由容器进行管理,但我们可以自定义初始化和销毁方法; 容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。

指定初始化和销毁方法方式

1、通过@Bean里的 init-method 和 destroy-method 指定 初始化方法 和 销毁方法

2、通过让Bean实现InitializingBean(定义初始化逻辑)、DisposableBean(定义销毁逻辑)

3、使用JSR250:

@PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法

@PreDestroy:在容器销毁bean之前通知我们进行清理工作

4、实现BeanPostProcessor-后置处理器:可以拦截bean初始化,并可以在被拦截的Bean的初始化前后进行一些处理工作。

postProcessBeforeInitialization: 在初始化之前工作

postProcessAfterInitialization: 在初始化之后工作

@Bean指定 初始化 和 销毁方法

使用xml的方式:

<bean id="cat" class="com.lly.pojo.Cat" init-method="init" destroy-method="destroy">

@Bean注解eg:pojo

public class Cat {

    public Cat() {
        System.out.println("Cat constructor");
    }

    public void init() {
        System.out.println("Cat init");
    }

    public void destroy() {
        System.out.println("Cat destroy");
    }
}

config配置类:

//指定Cat对象中哪个方法作为 初始化方法 和 销毁方法
    @Bean(initMethod = "init",destroyMethod = "destroy")
    public Cat cat() {
        return new Cat();
    }

调用:

 @Test
    public void test02() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config2.class);
        System.out.println("容器初始化完成……");
        context.close();
    }

输出:

Cat constructor
Cat init
容器初始化完成……
Cat destroy

以上是单例bean:
如果在config中配置:@Scope(“prototype”)
调用:

    public void test02() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config2.class);
        System.out.println("容器初始化完成……");
        //多实例bean只有调用的时候才会初始化bean
        context.getBean("cat");
        context.close();
    }

输出:

容器初始化完成……
Cat constructor
Cat init


多实例bean中,容器只负责创建,不会进行管理,所以不会调用销毁方法

实现 InitializingBean 和 DisposableBean

通过实现 InitializingBean 和 DisposableBean接口来实现afterPropertiesSet()初始化方法 和 destroy()销毁方法

pojo改进:

public class Cat implements InitializingBean , DisposableBean {

    public Cat() {
        System.out.println("Cat constructor");
    }

    public void init() {
        System.out.println("Cat init");
    }

//实现DisposableBean接口会有destroy()方法,所以原来的destroy()要加上@Override注解
    @Override
    public void destroy() {
        System.out.println("Cat destroy");
    }
    
//在属性赋值之后执行,即构造方法执行之后
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Cat afterPropertiesSet");
    }
}

输出:

Cat constructor
Cat afterPropertiesSet
Cat init
容器初始化完成……
Cat destroy

使用JSR250

通过使用 @PostConstruct 和 @PreDestroy 标注方法上来指定初始化和销毁方法

@PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法

@PreDestroy:在容器销毁bean之前通知我们进行清理工作

pojo改进:

public class Cat implements InitializingBean , DisposableBean {

    public Cat() {
        System.out.println("Cat constructor");
    }

    @PostConstruct
    public void preinit(){
        System.out.println("Cat preinit");
    }
    public void init() {
        System.out.println("Cat init");
    }

    @PreDestroy
    public void predestroy() {
        System.out.println("Cat predestroy");
    }
    
    @Override
    public void destroy() {
        System.out.println("Cat destroy");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Cat afterPropertiesSet");
    }
}

输出:

Cat constructor
Cat preinit
Cat afterPropertiesSet
Cat init
容器初始化完成……
Cat predestroy
Cat destroy

通过实现BeanPostProcessor-后置处理器

通过实现BeanPostProcessor接口的postProcessBeforeInitialization() 和 postProcessAfterInitialization()方法。
BeanPostProcessor: bean的后置处理器【在bean初始化前后进行一些处理工作】

     postProcessBeforeInitialization: 在初始化之前工作

     postProcessAfterInitialization: 在初始化之后工作

实现BeanPostProcessor接口:

@Component//加入到ioc容器
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization。。。" + beanName + "===>" + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization。。。" + beanName + "===>" + bean);
        return bean;
    }
}

输出:

postProcessBeforeInitialization。。。config2===>com.lly.Config.Config2$$EnhancerBySpringCGLIB$$3f1d8000@4b5a5ed1
postProcessAfterInitialization。。。config2===>com.lly.Config.Config2$$EnhancerBySpringCGLIB$$3f1d8000@4b5a5ed1
postProcessBeforeInitialization。。。config===>com.lly.Config.Config$$EnhancerBySpringCGLIB$$21979926@59d016c9
postProcessAfterInitialization。。。config===>com.lly.Config.Config$$EnhancerBySpringCGLIB$$21979926@59d016c9
postProcessBeforeInitialization。。。firstConreoller===>com.lly.controller.FirstConreoller@3cc2931c
postProcessAfterInitialization。。。firstConreoller===>com.lly.controller.FirstConreoller@3cc2931c
postProcessBeforeInitialization。。。secondController===>com.lly.controller.SecondController@20d28811
postProcessAfterInitialization。。。secondController===>com.lly.controller.SecondController@20d28811
postProcessBeforeInitialization。。。com.lly.pojo.Color===>com.lly.pojo.Color@3967e60c
postProcessAfterInitialization。。。com.lly.pojo.Color===>com.lly.pojo.Color@3967e60c
postProcessBeforeInitialization。。。person===>Person{id='1', name='zs', age=18}
postProcessAfterInitialization。。。person===>Person{id='1', name='zs', age=18}
postProcessBeforeInitialization。。。myFactoryBean===>com.lly.Config.MyFactoryBean@22a637e7
postProcessAfterInitialization。。。myFactoryBean===>com.lly.Config.MyFactoryBean@22a637e7
Cat constructor
postProcessBeforeInitialization。。。cat===>com.lly.pojo.Cat@4c9f8c13
Cat preinit
Cat afterPropertiesSet
Cat init
postProcessAfterInitialization。。。cat===>com.lly.pojo.Cat@4c9f8c13
容器初始化完成……
Cat predestroy
Cat destroy

在初始化方法的前后执行;无论是否有初始化和方法,他都会执行

BeanPostProcessor原理

可以在自定义的BeanPostProcessor中打一个断点,直接debug。

//给bean进行属性赋值
 this.populateBean(beanName, mbd, instanceWrapper);
 //BeanPostProcessor的执行在初始化bean方法内部
 exposedObject = this.initializeBean(beanName, exposedObject, mbd);

initializeBean:

if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        try {
        //执行自定义初始化方法
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
            throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
        }

        if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

applyBeanPostProcessorsBeforeInitialization:

    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;

        Object current;
        for(Iterator var4 = this.getBeanPostProcessors().iterator(); var4.hasNext(); result = current) {
            BeanPostProcessor processor = (BeanPostProcessor)var4.next();
            current = processor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
                return result;
            }
        }

        return result;
    }
原理:
遍历得到容器中所有的BeanPostProcessors;然后挨个执行postProcessBeforeInitialization,
一旦返回null,跳出for循环,不会执行后面的BeanPostProcessors.postProcessBeforeInitialization

BeanPostProcessor在Spring底层的使用

执行时机:

-doCreateBean
-populateBean():给bean的各种属性赋值
-initializeBean():初始化bean
-处理Aware方法
-applyBeanPostProcessorsBeforeInitialization:后置处理器的实例化前拦截
-invokeInitMethods:执行@Bean指定的initMethod
-applyBeanPostProcessorsAfterInitialization:后置处理器的实例化后拦截

应用:

-BeanValidationPostProcessor 用来实现数据校验

-AutowireAnnotationBeanPostProcessor, @Autowire实现(即怎么知道某个类标注了@Autowire注解)

-ApplicationContextProcessor 实现XXXAware的自动注入。

等。。。。
都有使用到BeanPostProcessor

通过实现ApplicationContextAware接口来实现保存applicationContext容器信息:

给Cat类中定义一个成员变量applicationContext,然后实现ApplicationContextAware接口,

再实现setApplicationContext方法,在方法中可以获取到ioc容器ApplicationContext applicationContext,

再通过this.applicationContext=applicationContext给Cat类中保存ioc容器信息
public class Cat implements InitializingBean , DisposableBean, ApplicationContextAware {

------省略一点内容---------


    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }

}

评论