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 指定的方法, 这与我们的输出顺序一致.
来源: http://www.bubuko.com/infodetail-3142085.html