注解-生命周期
我们在之前说到过bean的生命周期,其中提到了很多初始化方法,搞得我们晕头晕脑,本文就是来解决这个问题,对bean生命周期中重要的几个初始化和销毁接口或注解进行消息阐述,使得对bean的生命周期理解更加轻松。
1. @Bean指定初始化和销毁方法
bean生命周期:bean创建----初始化----销毁的过程
容器管理bean的生命周期,我们可以自定义初始化和销毁方法,容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
- 指定初始化和销毁方法
用xml配置的方式,可以指定init-method
和destory-method
;
那么注解如何做到自定义的初始化和销毁方法呢?
我们先来创建一个Dog的类:
1 | public class Dog { |
写一个配置类来注册这个Dog:
1 |
|
先来启动容器:
1 |
|
那么打印结果是:
1 | Dog constructor.... |
那如何指定我们自定义的初始化和销毁方法呢?
首先修改一下测试方法,增加一句关闭容器:
1 |
|
然后在@Bean注解上指定初始化方法和销毁方法:
@Bean(initMethod = “init”,destroyMethod = “destory”)
再次启动,显示:
1 | Dog constructor.... |
但是注意单例和多例的区别,现在我将其配置成多例,由于多例是每次访问才会创建bean,所以我们还需要访问一下。
最后的打印结果是:
1 | 容器已经启动成功... |
说明在多例的情况下,容器最后不会销毁这个bean。
⭐总结一下:
注解如何指定bean的初始化和销毁:@Bean注解后面指定init-method和destory-method
初始化:对象创建完成之后,并赋值好,在调用初始化方法
销毁方法:单例:容器关闭的时候销毁;多例:容器不会管理这个bean,容器不会调用销毁方法
2. InitializingBean和DisposableBean
除了上一种用@Bean
的方式来指定bean
的初始化和销毁之外,spring还提供了另外的方法来实现。
初始化:
让Bean
实现InitializingBean
接口并且实现它的afterPropertiesSet
方法,他的作用时机是:当一个BeanFactory
创建之后并且所有的属性值已经被设置完成之后,可以调用这个方法来进行初始化的工作。
1 | public interface InitializingBean { |
销毁:
让Bean
实现DisposableBean
接口并且实现destroy
方法,他的作用时机是BeanFactory
销毁的时候也将单实例bean给销毁掉。
1 | public interface DisposableBean { |
示例:
1 | public class Cat implements InitializingBean,DisposableBean{ |
最后打印一下,发现达到了一样的效果:
1 | cat constructor... |
3. @PostConstruct&@PreDestory
@PostConstruct
:bean创建好并且赋值好属性值之后执行一些初始化工作
@PreDestory
:在容器销毁bean之前通知我们进行清理工作
1 | public class Pig{ |
一样的效果。
4. BeanPostProcessor-后置处理器
这是一个接口,bean的后置处理器,在bean初始化前后进行一些处理工作,有两个方法,一个是初始化之前处理,一个是初始化之后处理。
具体的执行时机:
postProcessBeforeInitialization是在bean实例生成之后,在任何的初始化方法之前(比如InitializingBean接口的afterPropertiesSet方法;比如init-method方法)
postProcessAfterInitialization与上面个完全相反,在任何的初始化方法完成之后再调用。
1 | public interface BeanPostProcessor { |
示例:
我这里将上面的Dog,Cat,Pig全部用起来。pig用到init-destory和destory-method方法;cat实现InitializingBean,DisposableBean这两个接口;pig是实现@PostConstruct和@PreDestory这两个接口。
再加上后置处理器:
1 |
|
一起启动,看看是什么先后顺序:
1 | //1.首先是Dog对象创建 |
⭐⭐⭐其实顺序是这样的:Constructor
> @BeanPostProcessor
前置处理 > @PostConstruct
> InitializingBean
> init-method
> @BeanPostProcessor
后置处理
5. BeanPostProcessor原理
首先是创建IOC容器:
1 | AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); |
进去之后是构造器:
1 | public AnnotationConfigApplicationContext(Class... annotatedClasses) { |
这个refresh
方法中有finishBeanFactoryInitialization
这个方法:
1 | //初始化剩下的所有非懒记载的单例bean |
finishBeanFactoryInitialization
这个方法中有一个方法是:
1 | //真正初始化剩下的所有非懒记载的单例bean |
下面就是获取bean,获取不到就创建对象。
上面已经完成了对象的创建。下面就是进行属性赋值和初始化工作。
1 | 1、赋值 |
6. BeanPostProcessor在spring底层的使用
aop最基本的原理就是通过动态代理(jdk,cglib)来构造出一个代理对象,在容器创建bean的时候替换原来的bean。
是谁来创建这个代理对象呢?AnnotationAwareAspectJAutoProxyCreator
,这个玩意就是BeanPostProcessor
的某个子类。
关于Spring AOP的具体实现,还是比较复杂的,具体的代码以后再去研究,这里给出一个大概的步骤:
@EnableAspectJAutoProxy
会注册一个AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator
是一个InstantiationAwareBeanPostProcessor
- 创建流程
registerBeanPostProcessors()
注册后置处理器,创建
AnnotationAwareAspectJAutoProxyCreator
finishBeanFactoryInitialization
初始化剩下的单实例Bean
- 创建
Bean
和切面 AnnotationAwareAspectJAutoProxyCreator
拦截创建过程- 创建完
Bean
判断是否需要增强。通过BeanPostProcessorsAfterInitialization
,
wrapIfNecessary()
包装代理对象
- 创建
- 执行目标方法
- 获取拦截器链(
advisor
包装为Interceptor
) - 递归调用拦截器链
- 前置通知、目标方法、后置通知、返回通知、异常通知
- 获取拦截器链(
总结
- 执行初始化和销毁方法
- 通过
@Bean
指定init-destory
和destory-method
方法
- 通过
- 通过让
Bean
实现InitializingBean
(定义初始化逻辑),DisposableBean
(定义销毁前的逻辑) - 通过使用JSR250规范中的
@PostConstruct
和@PreDestory
来进行初始化工作和销毁之前的工作 BeanPostProcessor
:bean
的后置处理器,在bean
初始化前后进行一些处理工作