一、使用BeanPostProcessor定制bean
BeanPostProcessor
接口定义了回调方法
,你可以实现它来提供你自己的(或重载容器的默认)实例化逻辑,依赖解析逻辑等等。如果你想在Spring容器完成实例化,配置和初始化bean之后实现一些自定义逻辑,可以插入一个或多个BeanPostProcessor实现。
你可以配置多个BeanPostProcessor
实例,你可以通过设置order
属性来控制这些BeanPostProcessor的执行顺序。只有当BeanPostProcessor实现了“Ordered”接口时,才可以设置此属性;如果你写自己的BeanPostProcessor,你应该考虑实现“Ordered”接口。
BeanPostProcessor
操作bean(或对象)实例
; 也就是说,Spring IoC容器实例化一个bean实例,然后BeanPostProcessor
做他们的工作.BeanPostProcessor
的作用域是每个容器。 这仅在使用容器层次结构时才会用到这个。 如果你在一个容器中定义一个BeanPostProcessor
,它将只对该容器中的bean进行后处理。 换句话说,在一个容器中定义的bean不会被另一个容器中定义的BeanPostProcessor进行后处理,即使两个容器都是同一层次结构的一部分。
org.springframework.beans.factory.config.BeanPostProcessor
接口恰好包含两个回调方法。当这样的类在容器内注册为post-processor
,对于由容器创建的每个bean实例,容器创建所有bean,在容器初始化方法(比如InitializingBean
的afterProperieSet()
方法和其他所有的声明的init
方法)和所有bean 初始化回调之前,运行post-processor
回调。post-processor
可以对bean实例采取任何操作,包括完全忽略回调。 bean post-processor
通常检查回调接口或者可以用代理包装bean。一些Spring AOP基础结构类被实现为bean post-processor
,以便提供代理包装逻辑。
一个ApplicationContext
自动检测
在配置元数据中定义的实现BeanPostProcessor
接口的任何bean。 ApplicationContext
将这些bean注册为后处理器,以便稍后在创建bean时调用它们。 Bean后处理器可以像任何其他bean一样部署在容器中(直接使用<bean>)。
注意,当在配置类上使用@Bean
工厂方法声明BeanPostProcessor
时,工厂方法的返回类型应该是实现类本身或至少是org.springframework.beans.factory.config.BeanPostProcessor
接口,清楚地表明该bean的后处理器性质。否则,ApplicationContext
将不能在完全创建它之前通过类型自动检测它。因为BeanPostProcessor
需要尽早的实例化,以便应用于上下文中其他bean的初始化,所以这种尽早的类型检测是至关重要的。
二、使用BeanFactoryPostProcessor定制配置元数据
我们将要看到的下一个扩展点是“org.springframework.beans.factory.config.BeanFactoryPostProcessor”。这个接口的语义类似于BeanPostProcessor
,其中一个主要区别是:BeanFactoryPostProcessor对* bean配置元数据*操作;也就是说,Spring IoC容器允许BeanFactoryPostProcessor
读取配置元数据,并可能在容器实例化(除BeanFactoryPostProcessor之外的任何)bean之前改变它。
你可以配置多个BeanFactoryPostProcessor
s,你可以通过设置order
property来控制这些BeanFactoryPostProcessor的执行顺序。但是,如果BeanFactoryPostProcessor实现了 Ordered
接口,则只能设置此属性。如果你写自己的“BeanFactoryPostProcessor”,你应该考虑实现 Ordered
接口。
如果你想改变实际的bean 实例(即从配置元数据创建的对象),那么你需要使用一个BeanPostProcessor
述。虽然在技术上可以使用BeanFactoryPostProcessor(例如,使用BeanFactory.getBean()
)中的bean实例,这样做会导致提前的bean实例化,违反标准容器生命周期。这可能导致负面的副作用,如绕过bean后处理。此外,BeanFactoryPostProcessor
s的作用域也是在各自的容器内
。这仅在使用容器层次结构时才相关。如果你在一个容器中定义一个BeanFactoryPostProcessor
,它只会应用于该容器中的bean定义。一个容器中的Bean定义不会被另一个容器中的BeanFactoryPostProcessor进行后置处理,即使这两个容器都是同一层次结构的一部分。
接下里用代码来看看BeanPostProcessor和BeanFactoryPostProcessor
<!-- ContainnerDevelopment -->
<!-- 支持Spring注解 -->
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<!-- 注册一个BeanPostProcessor -->
<bean id="postProcessor" class="com.jay.document.containnerDevelop.PostProcessor"/>
<!-- 注册一个BeanFactoryPostProcessor -->
<bean id="factoryPostProcessor" class="com.jay.document.containnerDevelop.FactoryPostProcessor"/>
<!-- 普通bean -->
<bean id="beanFactoryPostProcessorTest" class="com.jay.document.containnerDevelop.BeanFactoryPostProcessorTest">
<property name="name" value="张三"/>
<property name="sex" value="男"/>
</bean>
上面的postProcessor实现了BeanPostProcessor接口,FactoryPostProcessor实现了BeanFactoryPostProcessor。
postProcessor:
public class PostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("后置处理器AfterInitialization()方法处理bean=【"+beanName+"】 开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("后置处理器BeforeInitialization()方法处理bean=【"+beanName+"】完毕!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return bean;
}
}
FactoryPostProcessor:
public class FactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("--->调用了BeanFactoryPostProcessor");
String[] beanStr = configurableListableBeanFactory
.getBeanDefinitionNames();
for (String beanName : beanStr) {
//这里输出 看看Bean配置的顺序
System.out.println("循环的beanName-->>"+beanName);
// 这里只改变beanFactoryPostProcessorTest的属性
if ("beanFactoryPostProcessorTest".equals(beanName)) {
BeanDefinition beanDefinition = configurableListableBeanFactory
.getBeanDefinition(beanName);
MutablePropertyValues m = beanDefinition.getPropertyValues();
System.out.println("--->>>"+m.getPropertyValueList().toString());
if (m.contains("name")) {
m.addPropertyValue("name", "李白");
System.out.println("--->修改了name属性初始值了");
}
}
}
}
}
BeanFactoryPostProcessorTest:
public class BeanFactoryPostProcessorTest implements InitializingBean,DisposableBean,BeanNameAware,BeanFactoryAware{
private String name;
private String sex;
public String getName() {
return name;
}
//getter setter
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("-->调用了BeanFactoryAware的setBeanFactory方法了");
}
@Override
public void setBeanName(String arg0) {
System.out.println("-->调用了BeanNameAware的setBeanName方法了");
}
@Override
public void destroy() throws Exception {
System.out.println("-->调用了DisposableBean的destroy方法了");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("-->调用了Initailization的afterPropertiesSet方法了");
}
@Override
public String toString() {
return "BeanFactoryPostProcessorTest [name=" + name + ", sex=" + sex + "]";
}
}
Test:
public static void main(String[] args) {
System.out.println("-->Spring ApplicationContext容器开始初始化了......");
ApplicationContext applicationcontext= new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("-->Spring ApplicationContext容器初始化完毕了......");
//BeanLifecycle beanLifecycle =applicationcontext.getBean("beanLifecycle",BeanLifecycle.class);
BeanFactoryPostProcessorTest beanFactoryPostProcessorTest=applicationcontext.getBean(BeanFactoryPostProcessorTest.class);
System.out.println(beanFactoryPostProcessorTest.toString());
}
运行结果 :
-->Spring ApplicationContext容器开始初始化了......
--->调用了BeanFactoryPostProcessor // 调用了 FactoryPostProcessor的postProcessBeanFactory方法
循环的beanName-->>myAware //这是通过@component注解配置的bean 在读取配置是在第一个
循环的beanName-->>org.springframework.context.annotation.internalConfigurationAnnotationProcessor
循环的beanName-->>org.springframework.context.annotation.internalAutowiredAnnotationProcessor
循环的beanName-->>org.springframework.context.annotation.internalRequiredAnnotationProcessor
循环的beanName-->>org.springframework.context.annotation.internalCommonAnnotationProcessor
循环的beanName-->>container //这是通过xml配置的bean
循环的beanName-->>atList //这是也通过xml配置的bean 顺序是按照配置的顺序
循环的beanName-->>org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#0
循环的beanName-->>postProcessor
循环的beanName-->>factoryPostProcessor
循环的beanName-->>beanFactoryPostProcessorTest // 这里可以看出 在bean没有实例化之前 ,就改变了 bean的属性配置
--->>>[bean property 'name', bean property 'sex'] // BeanFactoryPostProcessor 是对读取每个bean的配置文件都有效
--->修改了name属性初始值了 //
循环的beanName-->>org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor循环的beanName-->>org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor
后置处理器BeforeInitialization()方法处理bean=【myAware】完毕 // BeanPostProcessor 同样是对读取每个bean的配置文件都有效
后置处理器AfterInitialization()方法处理bean=【myAware】 开始
后置处理器BeforeInitialization()方法处理bean=【atList】完毕!
后置处理器AfterInitialization()方法处理bean=【atList】 开始
后置处理器BeforeInitialization()方法处理bean=【container】完毕!
后置处理器AfterInitialization()方法处理bean=【container】 开始
-->调用了BeanNameAware的setBeanName方法了
-->调用了BeanFactoryAware的setBeanFactory方法了//这里可以看出 BeanPostProcessor 的BeforeInitialization方法 执行 //在 Initailization的afterPropertiesSet方法之前
后置处理器BeforeInitialization()方法处理bean=【beanFactoryPostProcessorTest】完毕!
-->调用了Initailization的afterPropertiesSet方法了
后置处理器AfterInitialization()方法处理bean=【beanFactoryPostProcessorTest】 开始
-->Spring ApplicationContext容器初始化完毕了......
BeanFactoryPostProcessorTest [name=李白, sex=男] // 属性已经改变
三、 使用FactoryBean定制实例化逻辑
对象实现org.springframework.beans.factory.FactoryBean
接口,则成为它本身的工厂。
FactoryBean
接口是Spring IoC容器实例化逻辑的扩展点。假如初始化代码非常复杂,此时使用java编码比使用XML配置更容易表达。这种场景中,你可以创建自己的FactoryBean,在该类中编写复杂的初始化程序,然后将你的自定义FactoryBean插入到容器。
FactoryBean
接口提供了三种方法:
Object getObject()
:返回此工厂创建的对象的实例。实例可以共享,这取决于这个工厂是返回单例还是原型。boolean isSingleton()
:如果这个“FactoryBean”返回单例,则返回true
,否则返回false。类getObjectType()
:返回由getObject()
方法或null
返回的对象类型,如果类型不是预先知道的。
FactoryBean
概念和接口在Spring框架中的许多地方使用; Spring内置的有超过50个实现。
当你需要向容器请求一个实际的FactoryBean实例本身而不是它生成的bean时,在调用ApplicationContext的getBean()
方法时,用符号(&
)作为前缀。所以对于给定的FactoryBean
,id为myBean
,在容器上调用getBean(“myBean”)
会返回FactoryBean
所产生的bean;而调用getBean(“&myBean”)
返回FactoryBean
实例本身。
FactoryBean的核心就在于通过getObject方法可以获取的是它所生产的对象,所以我们在Proxy创建代理对象的时候就比较方便。还有一些bean,如果通过配置的方式,会显得比较麻烦和复杂,那么这时候适当的采用编码方式在某些场合下还是挺不错的。
给个小例子(来自此博)
- </span>public interface FactoryBean<T> {
- //返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中。
- T getObject() throws Exception;
- //返回FactoryBean创建的bean类型。
- Class<?> getObjectType();
- //返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。
- boolean isSingleton();
- }
- public class Person {
- private String name;
- private String address;
- private int age;
- }
- <bean id="personBean" class="com.gh.MavenTest.Person">
- <property name="name" value="gh1" />
- <property name="address" value="address1" />
- <property name="age" value="28" />
- </bean>
那么现在我们可以通过getBean("personBean")来获取该对象。那么我们来看下如果通过实现FactoryBean以后该怎么写呢?来看下我们的PersonFactoryBean的代码:
- public class PersonFactoryBean implements FactoryBean<Person>{
- private String personInfo;
- public Person getObject() throws Exception {
- Person person = new Person () ;
- String [] infos = personInfo.split ( "," ) ;
- person.setName(infos[0]);
- person.setAddress(infos[1]);
- person.setAge(Integer.parseInt(infos[2]));
- return person;
- }
- public Class<Person> getObjectType() {
- return Person.class;
- }
- public boolean isSingleton() {
- return true;
- }
- }
我们看到,这里PersonFactoryBean实现了FactoryBean接口,那么自然也要实现它定义的方法。这里我们是通过一个personInfo字符串解析得到Person对象,那么我们在配置Spring的时候就可以这么配置:
- <bean id="personFactory" class="com.hik.MavenTest.PersonFactory">
- <property name="personInfo" value="gh2,address2,22"></property>
- </bean>