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


一、使用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,在容器初始化方法(比如InitializingBeanafterProperieSet()方法和其他所有的声明的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之前改变它。

你可以配置多个BeanFactoryPostProcessors,你可以通过设置orderproperty来控制这些BeanFactoryPostProcessor的执行顺序。但是,如果BeanFactoryPostProcessor实现了 Ordered接口,则只能设置此属性。如果你写自己的“BeanFactoryPostProcessor”,你应该考虑实现 Ordered接口。

如果你想改变实际的bean 实例(即从配置元数据创建的对象),那么你需要使用一个BeanPostProcessor。虽然在技术上可以使用BeanFactoryPostProcessor(例如,使用BeanFactory.getBean())中的bean实例,这样做会导致提前的bean实例化,违反标准容器生命周期。这可能导致负面的副作用,如绕过bean后处理。此外,BeanFactoryPostProcessors的作用域也是在各自的容器内。这仅在使用容器层次结构时才相关。如果你在一个容器中定义一个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的实际应用,需要大家去发现理解。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值