您的位置:首页 > 编程语言 > Java开发

Spring容器扩展(BeanPostProcessor,BeanFactoryPostProcessor,FactoryBean)—Spring官方文档系列

2018-04-16 18:57 507 查看


一、使用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,如果通过配置的方式,会显得比较麻烦和复杂,那么这时候适当的采用编码方式在某些场合下还是挺不错的。

给个小例子(来自此博)

  1. </span>public interface FactoryBean<T> {  
  2.         //返回由FactoryBean创建的bean实例,如果isSingleton()返回true,则该实例会放到Spring容器中单实例缓存池中。  
  3.        T getObject() throws Exception;    
  4.        //返回FactoryBean创建的bean类型。  
  5.        Class<?> getObjectType();  
  6.        //返回由FactoryBean创建的bean实例的作用域是singleton还是prototype。  
  7.        boolean isSingleton();      
  8.     }  
  1. public class Person {  
  2.     private String name;  
  3.     private String address;  
  4.     private int age;  
  5. }  
  1. <bean id="personBean" class="com.gh.MavenTest.Person">  
  2.     <property name="name" value="gh1" />  
  3.     <property name="address" value="address1" />  
  4.     <property name="age" value="28" />  
  5. </bean>  

那么现在我们可以通过getBean("personBean")来获取该对象。那么我们来看下如果通过实现FactoryBean以后该怎么写呢?来看下我们的PersonFactoryBean的代码:

  1. public class PersonFactoryBean implements FactoryBean<Person>{  
  2.       
  3.     private String personInfo;  
  4.       
  5.     public Person getObject() throws Exception {  
  6.         Person person =  new  Person () ;      
  7.         String []  infos =  personInfo.split ( "," ) ;  
  8.         person.setName(infos[0]);  
  9.         person.setAddress(infos[1]);  
  10.         person.setAge(Integer.parseInt(infos[2]));  
  11.         return person;  
  12.     }  
  13.   
  14.     public Class<Person> getObjectType() {  
  15.         return Person.class;  
  16.     }  
  17.   
  18.     public boolean isSingleton() {  
  19.         return true;  
  20.     }  
  21. }  

我们看到,这里PersonFactoryBean实现了FactoryBean接口,那么自然也要实现它定义的方法。这里我们是通过一个personInfo字符串解析得到Person对象,那么我们在配置Spring的时候就可以这么配置:

  1. <bean id="personFactory" class="com.hik.MavenTest.PersonFactory">  
  2.     <property name="personInfo" value="gh2,address2,22"></property>  
  3. </bean>   
通过上面的小案例的代码,我们可以看到如果一个类实现了FactoryBean接口,那么getBean得到的不是他本身了,而是它所产生的对象,如果我们希望得到它本身,只需要加上&符号即可。至于FactoryBean的实际应用,需要大家去发现理解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐