天天看點

Spring後處理器使用解析 -- BeanFactoryPostProcessor和BeanPostProcessor一. 概念

前言

        有一篇非常不錯的文章:《Spring的BeanFactoryPostProcessor和BeanPostProcessor》,詳細的講解了Spring的兩種處理器的用法和Spring源碼實作,推薦大家閱讀

目錄

一. 概念

1.  BeanPostProcessor

2.  BeanFactoryPostProcessor  容器後處理器

3. Spring已有的BeanFactoryPostProcessor  

1.  PropertyPlaceholderConfigurer  

2.  PropertyOverrideConfigurer

3.  CustomAutowireConfigurer

4.  AutowiredAnnotationBeanPostProcessor 

5.  CustomScopeConfigurer  

一. 概念

    Spring後處理器,是Spring定義的功能接口Interface,包括兩種:

  • BeanPostProcessor   對容器中的Bean進行後處理,對Bean進行額外的加強
  • BeanFactoryPostProcessor  對Spring容器本身進行後處理,增強容器的功能

    後處理器接口同ApplicationContextAware、InitializingBean等接口不同,它們并非直接加在需要處理的bean類上,而是:

  1.  重新編寫一個後處理器類Class,類名中最好也帶上PostProcessor,好讓大家知道是個後處理器的實作;
  2. 将這個類implement後處理接口(BeanPostProcessor或者BeanFactoryPostProcessor),實作其中的方法;
  3. 然後再将此類在Spring容器中注冊為Bean。
  4. 當容器啟動或者有bean加載時,會自動調用實作了後處理器接口的方法,将bean作為參數傳入,進而實作相應的功能。
        對初級開發者而言,用BeanPostProcessor比較多一些,認識Spring的後處理器也是從此開始的。就功能而言,個人感覺BeanFactoryPostProcessor的功能更加強大些,而且Spring架構本身編寫了很多的實作了BeanFactoryPostProcessor接口的功能類,在spring容器啟動時進行很多初始化操作。

1.  BeanPostProcessor

        此接口包括兩個必須實作的方法:

//before
    Object postProcessBeforeInitialization(Object bean, String name);
    //after
    Object postProcessAfterInitialization(Object bean, String name);
           

    其中:

  • Object bean:即将進行後處理的bean執行個體;
  • String name 該bean的配置;傳回值是bean的Object。

        before和after是相對bean生命周期過程中,InitializingBean和<bean init="">來說的。spring會在Bean加載過程中,處理上面兩個初始化步驟的前後時間點上,分别調用對應的方法,完成必要的初始化操作。有關bean生命周期的順序,可以參考文檔《Spring Bean的生命周期》

當每個bean加載時,spring都會調用所有實作了BeanPostProcessor接口的後處理類方法,是以:
  1. 方法内一般都是先判斷bean的類型,篩選出所要處理的bean之後再進行後續操作
  2. BeanPostProcessor後處理器有處理一批bean的潛力,不是隻能對單個bean生效

2.  BeanFactoryPostProcessor  容器後處理器

        容器後處理器負責處理容器本身,接口方法有一個

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
           

    對容器進行處理,沒有傳回值

Spring本身提供了幾個實作了此接口的、非常有用的容器後處理器,下面可以看看

3. Spring已有的BeanFactoryPostProcessor  

  • PropertyPlaceholderConfigurer 屬性占位符配置器
  • PropertyOverrideConfigurer 重寫占位符配置器
  • CustomAutowireConfigurer 自定義自動裝配的配置器
  • AutowiredAnnotationBeanPostProcessor 自動裝配的配置器
  • CustomScopeConfigurer 自定義作用域的配置器

1.  PropertyPlaceholderConfigurer  

        PropertyPlaceholderConfigurer可以将上下文(配置檔案)中的屬性值放在另一個單獨的标準java Properties檔案中去。在XML檔案中用${key}替換指定的properties檔案中的值。這樣的話,隻需要對properties檔案進行修改,而不用對xml配置檔案進行修改。

<!-- 要使用@Value("${key}")方式配置property,則需要配置此BeanFactory後處理器 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
   <property name="location">
       <value>jdbc.properties</value>
   </property>

    <property name="fileEncoding">
        <value>UTF-8</value>
    </property>
</bean>
           

2.  PropertyOverrideConfigurer

        與PropertyPlaceholderConfigurer類似但不同,PropertyOverrideConfigurer 是修改已有的屬性。如果properties檔案中有bean屬性的内容,那麼就用properties檔案中的值來代替上下文中的 bean的屬性值。

<beans>
    <!-- 使用PropertyOverrideConfigurer修改屬性 -->
    <!-- dog.properties配置:aHuang.color=blue,将阿黃的顔色修改為藍色 -->
    <bean id="propertyConfigure" class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
        <property name="locations" value="classpath:dog.properties"/>
    </bean>

    <!-- bean狗:阿黃,顔色:黃色 -->
    <bean id="aHuang" class="org.leisu.Dog">
        <property name="name" value="aHuang"></property>
        <property name="color" value="yellow"></property>
    </bean>
</beans>
           

        可以看到,通過在dog.properties中配置:aHuang.color=blue,來修改bean:aHuang中已經配好的color=“yellow”,達到修改屬性的作用

3.  CustomAutowireConfigurer

        要了解CustomAutowireConfigurer的作用,需要先知道@Qualifier的功能。

       @Qualifier相關知識可以閱讀我另一篇文章《@Qualifier注解》學習

        @Qualifier可以實作自定義修飾注解的功能,例如:

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("Asian")         //使用@Qualifier自定義修飾注解Asian
public @interface Asian{ ... }

···············

//定義亞洲人
@Asian          //使用我們自定義的修飾注解
@Component
public class AsianMan extends Person {

}
           

為了避免對@Qualifier注解的任何依賴性,每個自定義注解上都用@Qualifier去修飾,可以在Spring中提供一個CustomAutowireConfigurer的bean定義,并直接注冊所有自定義注解類型:

<bean class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
   <property name="customQualifierTypes">
       <set>
           <value>org.leisu.Asian</value>
       </set>
   </property>
</bean>
           

        現在,自定義修飾符被顯式聲明了,就不再需要@Qualifier這個元注解符,也可以定義有qualifier特性的自定義注解了。

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
//不再使用@Qualifier自定義修飾注解Asian
public @interface Asian{ ... }
           
        相關知識也可以學習《注釋驅動的 IoC 功能》,很不錯的文章

4.  AutowiredAnnotationBeanPostProcessor 

     當 Spring 容器啟動時,AutowiredAnnotationBeanPostProcessor 将掃描 Spring 容器中所有 Bean,當發現 Bean 中擁有@Autowired 注釋時就找到和其比對(預設按類型比對)的 Bean,并注入到修飾的變量中。這個用法很常見,上面的案例也用到了@Autowired

  @Qualifier通過配置可以省略,在”3. CustomAutowireConfigurer”中已經有過讨論。而使用AutowiredAnnotationBeanPostProcessor, 也可以通過配置,增加或替換類似@Autowired的注解

//首先建立一個我們的注解
public @interface MyInject {
}


           

将@MyInject注解放入 AutowiredAnnotationBeanPostProcessor中,生成和@Autowired同樣的作用

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
   <!-- 增加自動注入的注解@MyInject -->
   <property name="autowiredAnnotationType" value="org.leisu.MyInject"/>
</bean>
           

編寫controller和service,使用 @MyInject注入service

//定義Controller
@Controller		
public class MyController {

	@MyInject				//使用我們自己定義的注解去注入
	private MyService myService;
	
	@ResponseBody
	@RequestMapping(value="/myInjectTest",method=RequestMethod.GET)
	public String myInjectTest() {
		return myService.service();
	}
}

           
//定義service
@Service
public class MyService {
	
	public String service() {
		return "this is a inject test";
	}
}
           

結果:

Spring後處理器使用解析 -- BeanFactoryPostProcessor和BeanPostProcessor一. 概念

上述方法暫時無法實作,以後再進行補充

5.  CustomScopeConfigurer  

        scope是控制bean作用域的屬性,可參考我另一篇文章《Spring Bean作用域》。

        除了在bean上直接設定外,也可以自定義一個作用域scope:

1.實作Scope接口的方法;

2使用後處理器CustomScopeConfigurer注冊。

示例如下:

public class MyScope implements Scope {
    private int index;
    private List objects = new LinkedList(); {
        objects.add(new TestBean());
        objects.add(new TestBean());
    }
    public String getConversationId() {
        return null;
    }
    public Object get(String name, ObjectFactory objectFactory) {
        if (index >= objects.size()) {
            index = 0;
        }
        return objects.get(index++);
    }
    public Object remove(String name) {
        throw new UnsupportedOperationException();
    }
    public void registerDestructionCallback(String name, Runnable callback) {
    }
}  
           
<bean id="myScope" class="MyScope"/>
<bean id="customerScope" class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="myScope">
                <bean class="myScope"/>
            </entry>
        </map>
    </property>
</bean>
<bean id="usesScope" class="org.springframework.beans.TestBean" scope="myScope"/>     
           

繼續閱讀