Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及
Bean 销毁前执行特定的操作,常用的设定方式有以下三种:
-
通过实现
InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法;
-
通过
<bean> 元素的 init-method/destroy-method属性指定初始化之后 /销毁之前调用的操作方法;
-
在指定方法上加上@PostConstruct
或@PreDestroy注解来制定该方法是在初始化之后还是销毁之前调用。
这是我们就有个疑问,这三种方式是完全等同的吗,孰先孰后?
下面我们将带着这个疑问,试图通过测试代码以及分析Spring源码找到答案。
首先,我们还是编写一个简单的测试代码:
public class InitSequenceBean implements InitializingBean {
public InitSequenceBean() {
System.out.println("InitSequenceBean: constructor");
}
@PostConstruct
public void postConstruct() {
System.out.println("InitSequenceBean: postConstruct");
}
public void initMethod() {
System.out.println("InitSequenceBean: init-method");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitSequenceBean: afterPropertiesSet");
}
}
并且在配置文件中添加如下Bean定义:
<bean class="InitSequenceBean"
init-method="initMethod"></bean>
好了,我们启动Spring容器,观察输出结果,就可知道三者的先后顺序了:
InitSequenceBean:
constructor
InitSequenceBean:
postConstruct
InitSequenceBean:
afterPropertiesSet
InitSequenceBean:
init-method
|
通过上述输出结果,三者的先后顺序也就一目了然了:
Constructor > @PostConstruct >
InitializingBean > init-method
先大致分析下为什么会出现这些的结果:构造器(Constructor)被率先调用毋庸置疑,InitializingBean先于init-method我们也可以理解(在也谈Spring容器的生命周期中已经讨论过),但是PostConstruct为何率先于InitializingBean执行呢?
我们再次带着这个疑问去查看Spring源代码来一探究竟。
通过Debug并查看调用栈,我们发现了这个类org.springframework.context.annotation.CommonAnnotationBeanPostProcessor,从命名上,我们就可以得到某些信息——这是一个BeanPostProcessor。想到了什么?在也谈Spring容器的生命周期中,我们提到过BeanPostProcessor的postProcessBeforeInitialization是在Bean生命周期中afterPropertiesSet和init-method之前执被调用的。
再次观察CommonAnnotationBeanPostProcessor这个类,它继承自InitDestroyAnnotationBeanPostProcessor。InitDestroyAnnotationBeanPostProcessor顾名思义,就是在Bean初始化和销毁的时候所作的一个前置/后置处理器。
通过查看InitDestroyAnnotationBeanPostProcessor类下的postProcessBeforeInitialization方法:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Couldn't invoke init method", ex);
}
return bean;
}
查看findLifecycleMetadata方法,继而我们跟踪到buildLifecycleMetadata这个方法体中,看下buildLifecycleMetadata这个方法体的内容:
private LifecycleMetadata buildLifecycleMetadata(final Class clazz) {
final LifecycleMetadata newMetadata = new LifecycleMetadata();
final boolean debug = logger.isDebugEnabled();
ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
if (initAnnotationType != null) {
if (method.getAnnotation(initAnnotationType) != null) {
newMetadata.addInitMethod(method);
if (debug) {
logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
}
if (destroyAnnotationType != null) {
if (method.getAnnotation(destroyAnnotationType) != null) {
newMetadata.addDestroyMethod(method);
if (debug) {
logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
}
}
});
return newMetadata;
}
分析这段代码发现,在这里会去判断某方法有没有被initAnnotationType/destroyAnnotationType注释,如果有,则添加到init/destroy队列中,后续一一执行。
initAnnotationType/destroyAnnotationType注释是什么呢,我们在CommonAnnotationBeanPostProcessor的构造函数中看到下面这段代码:
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
一切都清晰了吧。一言以蔽之,@PostConstruct注解后的方法在BeanPostProcessor前置处理器中就被执行了,所以当然要先于InitializingBean和init-method执行了。
最后,给出本文的结论,Bean在实例化的过程中:
Constructor > @PostConstruct >
InitializingBean > init-method
本文源代码下载:https://lb-multi-demo.googlecode.com/svn/trunk/spring-lifecycle-test
By Mr.Chris
分享到:
相关推荐
java @PostConstruct和@PreConstruct注解整理.........
获取springbean对象
@postConstruct 所标注的方法 内部是靠的spring提供的两个后置处理器(InitDestroyAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor)共同 协调分布处理完成的。 这2点也是网上绝大部人没讲明白的...
NULL 博文链接:https://nhy520.iteye.com/blog/889276
主要介绍了SpringBoot @PostConstruct原理用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要给大家介绍了关于Spring定时任务中@PostConstruct被多次执行异常的分析与解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
为了定义一个 bean 的安装和卸载,我们可以使用 init-method 和 destroy-method 参数简单的声明一下 ,其中 init-method 属性指定了一个方法,该方法在 bean 的实例化阶段会立即被调用;同样地,destro
主要介绍了Spring实战之使用@POSTConstruct和@PreDestroy定制生命周期行为操作,结合实例形式详细分析了Spring使用@POSTConstruct和@PreDestroy定制生命周期相关接口定义、配置与功能实现技巧,需要的朋友可以参考下
coffeebeans-基于htmlhammer的微型javascript框架展示柜# Header.coffeeHeader = Bean () -> @ postConstruct = => console . log " Constructed Header " div class : " header " style : backgroundColor : " ...
init-method destroy-method API BeanFactory:使用这个工厂创建对象的方式都是懒加载,在调用的时候再创建 ClassPathXmlApplicationContext:使用这个工厂创建对象,他会根据scope智能判断是否懒加载,如果是...
3、通过spring的xml bean配置或bean注解指定初始化方法,如下面实例的initMethod方法通过@bean注解指定。 销毁的时候实现的方法 1、通过java提供的@PreDestroy注释; 2、通过实现spring提供的DisposableBean接口,并...
ip2region-spring-boot-starter 用于ip2region的Spring Boot Starter说明基于ip2region的Spring Boot Starter实现最新IP数据下载地址: : ...import javax.annotation.PostConstruct ;import org.springframework.beans
xml java系统源码 springdemo spring3的IOC,AOP,JDBC,orm等各个模块的使用示例集锦,可以作为入门...init-method,destroy-method,initiableBean, DisposableBean,lasyinit,singleton,prototype @PostConstruct @P
spring 注解初始化,初始化开始@postconstruct 对象销毁@predestroy javax.annotation.jar文件
@JsonPropertyOrder , @JsonSerialize , @JsonSetter , @Lazy , @Order , @PathVariable , @Pointcut , @PostConstruct , @PostMapping , @PreDestroy , @Primary , @PropertySource , @Qualifier , @Repository , ...
注解介绍等详细说明及使用: • @Controller • @Service ... • @PostConstruct • @PreDestroy • @Repository • @Component (不推荐使用) • @Scope • @SessionAttributes • @InitBinder
(二) init-method destroy-method 不要和prototype一起用(了解) 15 第六课:annotation方式Spring 16 一、 开始使用annotation配置Spring 16 二、 @Autowired、@Qualifier 16 (一) @Autowired 16 (二) @Qualifier ...
(二) init-method destroy-method 不要和prototype一起用(了解) 15 第六课:annotation方式Spring 16 一、 开始使用annotation配置Spring 16 二、 @Autowired、@Qualifier 16 (一) @Autowired 16 (二) @Qualifier ...
@PostConstruct and @PreDestroy. DETAILS Please see the doc at https://github.com/Netflix/governator/wiki BUILDING Governator is built via Gradle (http://www.gradle.org). To build from the command line...