1. 什么是BeanPostProcessor
BeanPostProcessor是一个接口,有两个方法,分别是:Object postProcessBeforeInitialization(Object var1, String var2) throws BeansException 和 Object postProcessAfterInitialization(Object var1, String var2) throws BeansException;
Spring Bean的生命周期中,在为Bean实例化,装配好属性后,会调用上下文中所有的BeanPostProcessor对象的两个方法为其初始化;

2. 一个小例子
分别创建三个类,分别是接口类、接口类的实现类,和BeanPostProcessor的实现类。

 package com.khlin.my.test;

 public interface WelcomeService {

     void welcome();
}
 package com.khlin.my.test;

 import org.springframework.beans.factory.InitializingBean;

 public class WelcomeServiceImpl implements WelcomeService, InitializingBean {

     public void init() {
System.out.println("init.");
} public void welcome() {
System.out.println("Welcome to Spring.");
} public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet.");
}
}
 package com.khlin.my.test;

 import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; public class LoginProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("login successfully.");
return o;
} public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("logout successfully.");
return o;
}
}

在applicationContext.xml里实例化对应的Bean.

 <bean id="welcomeService" class="com.khlin.my.test.WelcomeServiceImpl" init-method="init"/>
<bean id="loginProcessor" class="com.khlin.my.test.LoginProcessor"/>

再写一个启动类

 package com.khlin.my.test;

 import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class IOCTest { public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
System.out.println("context 启动成功");
WelcomeService messageService = context.getBean(WelcomeService.class);
messageService.welcome();
}
}

启动main方法,输出如下:

调用顺序分别为:

BeanPostProcessor的postProcessBeforeInitialization

InitializingBean的afterPropertiesSet

init方法

BeanPostProcessor的postProcessAfterInitialization

3. 实现原理

我们来看一下Spring启动一个上下文的时候,都做了啥。这里不作详细的源码解读。

可以看到上下文ApplicationContext持有一个BeanFactory。在第一个红框,将所有的BeanPostProcessor注册到BeanFactory。

调试代码,可以看到注册后保存在BeanFactory的beanPostProcessors集合里。

再来看第二个红框,finishBeanFactoryInitialization() 这个方法会对Bean进行初始化。

在AbstractAutowireCapableBeanFactory这个类的protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)方法里,可以看到invokeInitMethods方法被夹在BeanPostProcessor两个方法的中间。

在applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization方法中,会遍历所有注册的BeanBeanProcessor并调用方法。

每个BeanPostProcessor可以返回处理后的对象,如果返回null,会导致遍历中断,可能有些BeanPostProcessor无法处理,这点要注意。

InitMethod有两种方式,一种是在配置文件中加上init-method属性并指定对应的方法,另一种是实现InitializingBean接口的afterPropertiesSet()方法。

可以看到是优先调用afterPropertiesSet()方法,再调用init-method指定的方法,这与我们的输出顺序一致。

 4. 总结

Spring Bean的生命周期,在初始化阶段的调用顺序为:

  BeanPostProcessor的postProcessBeforeInitialization

  InitializingBean的afterPropertiesSet

  init方法

  BeanPostProcessor的postProcessAfterInitialization

如果有一个BeanPostProcessor返回null,会导致遍历的中断,可能有些BeanPostProcessor无法调用。因此一般不返回null.

最新文章

  1. JavaScript对象和数组
  2. c#_图表之zeGraph
  3. CAS 4.0.0RC 配置MD5验证功能
  4. SQLServer语句 汇总
  5. 奥威power-BI 在线体验平台
  6. 242. Valid Anagram
  7. UVaLive 7370 Classy (排序,比较)
  8. Android应用程序框架之无边界设计意图
  9. delphi编程里的bool跟boolean类型有什么区别
  10. 转:Server.MapPath相关
  11. Windows窗口消息大全(转)
  12. 两种Data Table参数化设置的区别
  13. php opcode缓存
  14. Xamarin Layout属性(转)
  15. T-SQL流程控制语句
  16. Nest + typeorm
  17. Java中常见的排序方式-快速排序(升序)
  18. odoo11 添加自定义模块报错问题
  19. 解决 https urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] 错误
  20. Python2.7-hmac

热门文章

  1. OpenResty之 lua_shared_dict 指令
  2. 黑马vue---56-58、vue组件创建的三种方式
  3. JAVA基于File的基本的增删改查
  4. Python 数据库的Connection、Cursor两大对象
  5. epoll简介 与 UDP server的实现
  6. SpringBoot学习之一 Unable to find a single main class from the following candidates
  7. cv2.bitwise_and的应用,
  8. Python简单遍历字典及删除元素的方法
  9. Node.js使用Express实现Get和Post请求
  10. xcode报错: 找不到路径或者资源错误:no such file or directory