BeanFactoryPostProcessor
上篇介绍了BeanPostProcessor(后面以Post代替),这篇讲的是BeanFactoryPostProcessor(后面以PostFactory代替),后者也是可以修改Bean的配置。
1.它们的区别是什么?不是网上说的“BeanPostProcessor不能够修改Bean的配置,而BeanFactoryPostProcessor可以”,实际上两者都是可以,它们的区别实际上是,对Bean的修改的“层面”不同;
做一个这样的比喻,类Bean是一个模具,实例化后的bean是从模具中出来的模型,PostFactory是作用是修改这个模具,而Post作用是修改放入模具中的产品的原料以及修改从模具中出来的产品的原料。 整个过程就是这样的,Spring找到Bean模具,PostFactory修改模具,Post先改变原料,然后放入Bean这个模具,产品出来后Post再次修改这个产品。
2.PostFactory如何使用?
我们看一下源代码:
PostProcessor的注册位于Bean的加载之后和Post的注册之前;进入到这个invokeBeanFactoryPostProcessors的内部:
上面的第一个方法getBeanNamesForType查找所有实现BeanFactoryPostProcessor的类,然后通过add方法把这些类加入到无序的List中(其中也有有序List),说明支持BeanFactoryPostProcessor的排序。最后invokeBeanFactoryPostProcessors方法真正执行所有的实现类(nonOrderedPostProcessors);下面实例演示它的用法。
3.在演示之前,对于Post除了前面文章的讲述外,还有一个细节:继续上一篇文章,我们仍然分析下面这个方法doCreateBean
上图两个方法都是在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory中的doCreateBean方法中的,第一个方法执行构造函数,第二个方法如下:
4.到此为止,执行顺序全部清楚了,下面贴上实例:
App.java
package com.mycompany.app;
import org.springframework.beans.factory.InitializingBean;
public class App implements InitializingBean
{
private App(){
System.out.println("App.App()");
}
private String says="App";
public String getSays() {
return says;
}
public void setSays(String says) {
this.says = says;
}
public void say(){
System.out.println("App.app():"+says);
}
/**
* 在构造函数和getset方法之后执行postProcessBeforeInitialization方法
*/
/*这个方法是InitializingBean在继承InitializingBean接口后,要实现的方法,顾名思义,是在
*属性设置之后进行一些操作*/
public void afterPropertiesSet() throws Exception {
System.out.println("App.afterPropertiesSet()");
}
/*这个方法是在Spring配置中通过init-method属性指定为该方法,然后才会执行,在afterPropertiesSet方法之后*/
public void initMethod(){
System.out.println("App.initMethod()");
}
/**
*在afterPropertiesSet和initMethod方法之后执行postProcessAfterInitialization方法
*/
}
BeanPostProcessorApp.java
package com.mycompany.app;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class BeanPostProcessorApp implements BeanPostProcessor{
/*如果打印结果出现该字符串,证明进行了初始化*/
private BeanPostProcessorApp(){
System.out.println("BeanPostProcessorApp.BeanPostProcessorApp()");
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if(bean instanceof App){
((App)bean).setSays("Before:BeanPostProcessorApp");
System.out
.println("BeanPostProcessorApp.postProcessBeforeInitialization()");
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if(bean instanceof App){
((App)bean).setSays("After:BeanPostProcessorApp");
System.out
.println("BeanPostProcessorApp.postProcessAfterInitialization()");
}
return bean;
}
}
BeanFactoryPostProcessorApp.java
package com.mycompany.app;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class BeanFactoryPostProcessorApp implements BeanFactoryPostProcessor{
private BeanFactoryPostProcessorApp() {
System.out.println("BeanFactoryPostProcessorApp.BeanFactoryPostProcessorApp()");
}
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = (BeanDefinition)beanFactory.getBeanDefinition("app");
beanDefinition.setAttribute("says", "BeanFactoryPostProcessor");
System.out
.println("BeanFactoryPostProcessorApp.postProcessBeanFactory(): "+beanDefinition.getAttribute("says"));
}
}
SpringBean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<bean id="app" class="com.mycompany.app.App" init-method="initMethod"></bean>
<bean id="beanPostProcessorApp" class="com.mycompany.app.BeanPostProcessorApp"></bean>
<bean id="beanFactoryPostProcessorApp" class="com.mycompany.app.BeanFactoryPostProcessorApp"></bean>
</beans>
BeanFactoryPostProcessorAppTest.java
package com.mycompany.app;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanFactoryPostProcessorAppTest {
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringBean.xml");
App app = (App)applicationContext.getBean("app");
app.say();
}
}
整体目录如下(AppTest...等三个文件,内容其实是一样的):
运行BeanFactoryPostProcessorAppTest.java,结果如下,和上面的分析是一致的: