BeanPostProcessor的作用是在调用初始化方法的前后添加一些逻辑,这里初始化方法是指在配置文件中配置init-method,或者实现了InitializingBean接口的afterPropertiesSet方法,注意不包括@PostConstruct这种初始化方式。可以看源码AbstractAutowireCapableBeanFactory类中的invokeInitMethods方法。
1.用法
新建Student类
package com.demo.spring.entity; import javax.annotation.PostConstruct; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Component; /** * @author chenyk * @date 2018年5月8日 */ @Component("student") public class Student{ private String name; private int age; private School school; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public School getSchool() { return school; } public void setSchool(School school) { this.school = school; } public void init(){ System.out.println("执行 init方法"); } }
创建实现了BeanPostProcessor接口的后置处理器StudentBeanPostProcessor
package com.demo.spring.entity; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; /** * Bean后置处理器 * @author chenyk * @date 2018年6月29日 */
//以下这两个方法不能返回null,否则在调用初始化方法时会报空指针异常;因为后置处理器从springIOC容器中取出bean实例后需要再把bean实例放回去 public class StudentBeanPostProcessor implements BeanPostProcessor{ /** * 在bean实例调用初始化方法之前调用 */ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("student")){ System.out.println("开始调用init方法"); } return bean; } /** * 在bean实例调用初始化方法之后调用 */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("student")){ System.out.println("init方法调用结束"); } return bean; } }
在配置文件aop.xml中添加以下信息
<bean id="student" class="com.demo.spring.entity.Student" init-method="init" > <property name="name" value="张三"></property> </bean>
<!-- spring会自动检测实现了BeanPostProcessor接口的类,并将其注册为后置处理器 --> <bean id="studentBeanPostProcessor" class="com.demo.spring.entity.StudentBeanPostProcessor" />
测试方法
@Test public void testAop5(){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("aop.xml"); }
看下打印信息:
开始调用init方法
2018-07-02 13:58:47,519 DEBUG [AbstractAutowireCapableBeanFactory.java:1731] : Invoking init method 'init' on bean with name 'student' //这一行信息,就是即将调用init-method方法的日志打印
执行 init方法
init方法调用结束
需要注意的是,如果一个类实现了BeanPostProcessor接口,那么这个类就作用于所有的bean实例,我们可以在BeanPostProcessor接口的两个方法中添加自己的控制和逻辑;
2.源码分析
2.1 找到实现BeanPostProcessor接口的类,并将其注册为后置处理器,看源码
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); //发现注册bean后置处理器,在这个方法中进行 // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
2.2 后置处理器生效的地方,进入AbstractAutowireCapableBeanFactory类中的initializeBean方法
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { invokeAwareMethods(beanName, bean); return null; } }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean;
//后置处理器的postProcessBeforeInitialization方法 if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } //调用初始化方法有:init-method,实现了InitializingBean接口的方法 try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); }
//后置处理器的postProcessAfterInitialization方法 if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }