转自:https://blog.csdn.net/liuchuanhong1/article/details/52939353
参考:https://blog.csdn.net/heyutao007/article/details/50326793
最近在项目中需要封装kafka的服务,其中使用到了工厂模式,该模式涉及到了Spring Bean的初始化和销毁,如是研究了一番,总结如下,和大家共勉之
Spring Bean的初始化和销毁Bean有几种方法了?答案是3种
方法一:使用@PostConstruct注解初始化,使用@PreDestroy注解销毁Bean
示例代码如下:
- public class PostConstructInit {
- @PostConstruct
- public void PostConstruct() {
- System.out.println("执行PostConstructInit: PostConstruct");
- }
- @PreDestroy
- public void PreDestory(){
- System.out.println("执行PostConstructInit: PreDestory");
- }
- public static void main(String[] args) {
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
- "classpath:beans.xml");
- context.close();
- }
- }
配置文件如下:
- <context:annotation-config/>
- <context:component-scan base-package="com.chhliu.myself.spring.test"></context:component-scan>
- <bean id="postConstructor" class="com.chhliu.myself.spring.test.PostConstructInit"></bean>
测试结果如下:
执行PostConstructInit: PostConstruct 执行PostConstructInit: PreDestory |
方法二:实现InitializingBean, DisposableBean这两个接口,并复写afterPropertiesSet()和destroy()方法
示例代码如下:
- public class InitializingDisposableInit implements InitializingBean,
- DisposableBean {
- @Override
- public void destroy() throws Exception {
- System.out.println("执行InitializingDisposableInit: destroy");
- }
- @Override
- public void afterPropertiesSet() throws Exception {
- System.out.println("执行InitializingDisposableInit: afterPropertiesSet");
- }
- public static void main(String[] args) {
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
- "classpath:beans-impl.xml");
- context.close();
- }
- }
执行InitializingDisposableInit: afterPropertiesSet 执行InitializingDisposableInit: destroy |
方法三:使用init-method和destroy-method配置方法
示例代码如下:
- public class MethodInit {
- public void initMethod() {
- System.out.println("执行MethodInit: init-method");
- }
- public void destroyMethod() {
- System.out.println("执行MethodInit: destroy-method");
- }
- public static void main(String[] args) {
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
- "classpath:beans-method.xml");
- context.close();
- }
- }
配置文件如下:
- <bean id="methodInit" class="com.chhliu.myself.spring.test.MethodInit" init-method="initMethod" destroy-method="destroyMethod"></bean>
执行MethodInit: init-method 执行MethodInit: destroy-method |
那么三种初始化和销毁Spring Bean的方式就讲完了,那么这三种方式的执行顺序是如何了,我们接着来做个测试
测试代码如下:
- public class InitAndDestroySeqBean implements InitializingBean, DisposableBean {
- public InitAndDestroySeqBean() {
- System.out.println("执行InitAndDestroySeqBean: 构造方法");
- }
- @PostConstruct
- public void postConstruct() {
- System.out.println("执行InitAndDestroySeqBean: postConstruct");
- }
- @Override
- public void afterPropertiesSet() throws Exception {
- System.out.println("执行InitAndDestroySeqBean: afterPropertiesSet");
- }
- public void initMethod() {
- System.out.println("执行InitAndDestroySeqBean: init-method");
- }
- @PreDestroy
- public void preDestroy() {
- System.out.println("执行InitAndDestroySeqBean: preDestroy");
- }
- @Override
- public void destroy() throws Exception {
- System.out.println("执行InitAndDestroySeqBean: destroy");
- }
- public void destroyMethod() {
- System.out.println("执行InitAndDestroySeqBean: destroy-method");
- }
- public static void main(String[] args) {
- ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
- "classpath:applicationContext.xml");
- context.close();
- }
- }
测试结果如下:
- 执行InitAndDestroySeqBean: 构造方法
- 执行InitAndDestroySeqBean: postConstruct
- 执行InitAndDestroySeqBean: afterPropertiesSet
- 执行InitAndDestroySeqBean: init-method
- 执行InitAndDestroySeqBean: preDestroy
- 执行InitAndDestroySeqBean: destroy
- 执行InitAndDestroySeqBean: destroy-method
最后我们得出的结果如下:
- 初始化顺序:
- Constructor > @PostConstruct >InitializingBean > init-method
- 销毁的顺序如下:
- @PreDestroy > DisposableBean > destroy-method
1、如果我们在afterPropertiesSet()方法中抛出异常,那么初始化会被终止,不会执行后面的init-method对应的初始化方法
2、Spring中初始化的Bean的类为
Org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
3、afterPropertiesSet()方法的效率比init-method高,因为init-method使用的是反射来寻找对应的方法,而afterPropertiesSet()则是直接执行的,相关源码如下:
- init-method:
- String initMethodName = mbd.getInitMethodName();
- final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
- BeanUtils.findMethod(bean.getClass(), initMethodName) :
- ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
- 从上面的代码可以看出,使用的是放射方式
- afterPropertiesSet():
- protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
- throws Throwable {
- // 如果存在afterPropertiesSet方法且实例是InitializingBean类型的话,就直接执行afterPropertiesSet()方法
- boolean isInitializingBean = (bean instanceof InitializingBean);
- if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
- if (logger.isDebugEnabled()) {
- logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
- }
- if (System.getSecurityManager() != null) {
- try {
- AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
- public Object run() throws Exception {
- ((InitializingBean) bean).afterPropertiesSet();
- return null;
- }
- }, getAccessControlContext());
- }
- catch (PrivilegedActionException pae) {
- throw pae.getException();
- }
- }
- else {
- ((InitializingBean) bean).afterPropertiesSet();
- }
- }
- }
4、init-method只能是无参无返回的public方法
通过上述输出结果,说明三种初始化的顺序是:
Constructor > @PostConstruct > InitializingBean > init-method
原因:
@PostConstruct注解后的方法在BeanPostProcessor前置处理器中就被执行了。我们知道BeanPostProcessor接口是一个回调的作用,Spring容器的每个受管Bean在调用初始化方法之前,都会获得BeanPostProcessor接口实现类的一个回调。在BeanPostProcessor的方法中有一段逻辑就是会判断当前被回调的bean的方法中有没有被initAnnotationType/destroyAnnotationType注释,如果有,则添加到init/destroy队列中,后续一一执行。initAnnotationType/destroyAnnotationType注解就是@PostConstruct/@PreDestroy。所以@PostConstruct当然要先于InitializingBean和init-method执行了。
从图中,我们可以看到实例化Bean的过程中有以下几个节点:
1)设置属性值;
2)调用Bean中的BeanNameAware.setBeanName()方法,如果该Bean实现了BeanNameAware接口;
3)调用Bean中的BeanFactoryAware.setBeanFactory()方法,如果该Bean实现了BeanFactoryAware接口;
4)调用BeanPostProcessors.postProcessBeforeInitialization()方法;@PostConstruct注解后的方法就是在这里被执行的
5)调用Bean中的afterPropertiesSet方法,如果该Bean实现了InitializingBean接口;
6)调用Bean中的init-method,通常是在配置bean的时候指定了init-method,例如:<bean class="beanClass" init-method="init"></bean>
7)调用BeanPostProcessors.postProcessAfterInitialization()方法;
8)如果该Bean是单例的,则当容器销毁并且该Bean实现了DisposableBean接口的时候,调用destory方法;如果该Bean是prototype,则将准备好的Bean提交给调用者,后续不再管理该Bean的生命周期。