- 浏览: 297163 次
- 性别:
- 来自: 安徽
文章分类
最新评论
-
fanjf:
因为不是太懂,所以摘录!
DataStage---向目的库插入时出现问题:MLOG$ -
fanjf:
oracle 位图索引:位图索引: 解决某一表数据很多,但某一 ...
【转】 mysql 添加列,修改列,删除列。 -
fanjf:
创建索引:CREATE TABLE mm (m1 CHAR(1 ...
【转】 mysql 添加列,修改列,删除列。 -
fanjf:
查询mysql 的表emp 的约束:
SELECT * FR ...
【转】 mysql 添加列,修改列,删除列。 -
fanjf:
为什么 update 不报错,结果为空?
关于MYSQL 检查check约束
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" );
- }
- }
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;
- }
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;
- }
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" );
- }
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
发表评论
-
org.springframework.dao.DataAccessResourceFailureException Io 异常: tConnection re
2014-02-14 11:05 2307最近程序老是出现等待一会后 操作程序页面 出现下面异常 ... -
MyBatis3整合Spring3的Transaction事务处理
2012-03-19 10:48 928正如第二版,Spring 仅支持 iBatis2。那么我们就想 ... -
MyBatis3整合Spring3、SpringMVC3
2012-03-19 10:47 1084开发环境: System:Windows ... -
FreeMarker配置详解
2012-03-16 16:52 2112<? xml version="1.0&qu ... -
FreeMarker整合Spring 3.0
2012-03-16 16:39 912开发环境: System:Windows We ... -
Spring 的AOP(面向切面编程)
2012-03-05 17:59 949AOP 是一门编程技术, spring 的 ... -
spring 配置完Service怎么得到Action
2012-02-29 16:36 1290写一个手机发送短信的后台处理在包装短信时,今天遇到一个问题: ... -
Spring的优点:
2012-02-21 19:28 761Spring带给我们什么: ◆方便解耦,简化开发 ... -
Spring中两种注入方式的对比
2012-02-21 19:26 1238spring依赖注入的两种方式: 1.设置注入; 2.构造 ... -
spring中bean继承与java继承的区别
2012-02-21 19:25 8331.Spring中子bean和父bean可以是不同类型,jav ... -
spring依赖关系配置
2012-02-21 19:25 995依赖注入--如果A依赖于B,则B实例不再由A负责生成,而有容器 ... -
Spring 依赖检查
2012-02-21 19:24 871在进行说明bean依赖检查的几种模式前,先给大家说明我们为什么 ... -
Spring内核研究-管理bean的声明周期一(InitializingBean和init-method)
2012-02-20 10:01 1028... -
也谈Spring Bean的生命周期
2012-02-15 17:26 999开篇先用一张老图描述下 Spring 中 Bean ... -
Spring的InitializingBean和init-method
2012-02-15 17:24 890Spring在设置完一个bean所有的属性后,会检查bean是 ... -
Spring的init-method 与afterPropertiesSet
2012-02-15 17:22 1345init-method 与afterPropertiesSet ... -
Spring事务配置的五种方式
2012-02-15 16:55 678前段时间对Spring的事务配置做了比较深入的研究,在此之间对 ...
相关推荐
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...