1. 程式人生 > >Spring 中如何自動創建代理(spring中的三種自動代理創建器)

Spring 中如何自動創建代理(spring中的三種自動代理創建器)

名稱 ann 1.0 lib align 織入 efault top get

Spring 提供了自動代理機制,可以讓容器自動生成代理,從而把開發人員從繁瑣的配置中解脫出來 。 具體是使用 BeanPostProcessor 來實現這項功能。

這三種自動代理創建器 為:BeanNameAutoProxyCreator , DefaultAdvisorAutoProxyCreator , AbstractAdvisorAutoProxyCreator。

1BeanPostProcessor

BeanPostProcessor 代理創建器的實現類可以分為 3 類:

類型實現類
基於 Bean 配置名規則 BeanNameAutoProxyCreator
基於 Advisor 匹配規則 DefaultAdvisorAutoProxyCreator
基於 Bean 中的 AspectJ 註解標簽的匹配規則 AnnotationAwareAspectJAutoProxyCreator

技術分享圖片

BeanPostProcessor 類繼承關系

所有的自動代理器類都實現了 BeanPostPorcessor ,在容器實例化 Bean 時, BeanPostProcessor 將對它進行加工處理,所以自動代理創建器能夠對滿足匹配規則的 bean 自動創建代理對象。

2 BeanNameAutoProxyCreator

假設有以下兩個實體類(用戶與充電寶)。

用戶類:

public class User {

    public void rent(String userId) {
        System.out.println("User:租賃【充電寶】");
    }

    public void back(String userId){
        System.out.println("User:歸還【充電寶】");

    }
}

充電寶:

public class Charger {

    public void rent(String userId) {
        System.out.println(
"Charger:【充電寶】被租賃"); } }

我們希望通過 BeanNameAutoProxyCreator 通過 Bean 的名稱來自動創建代理,實現增強:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

    <bean id="user" class="net.deniro.spring4.aop.User"/>
    <bean id="charger" class="net.deniro.spring4.aop.Charger"/>

    <!-- 前置增強-->
    <bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/>

    <!-- 使用 BeanNameAutoProxyCreator-->
    <bean
            class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
            p:beanNames="*er"
            p:interceptorNames="rentBeforeAdvice"
            p:optimize="true"
            ></bean>
</beans>

BeanNameAutoProxyCreator的 beanNames 屬性允許指定一組需要自動代理的 Bean 名稱, 這裏可以使用 * 通配符 。

因為我們需要代理的類名分別是 user 與 charger,都是以 er 結尾的,所以我們這裏定義為 *er

也可以通過 beanNames 的 value 值來明確指定需要代理的 Bean 名稱,多個以逗號分隔(更常用)。

<!-- 指定自動代理的 Bean 名稱-->
<property name="beanNames" value="user,charger">
</property>

也可以通過 list 方式來指定 beanNames 的值:

<property name="beanNames">
    <list>
        <value>user</value>
        <value>charger</value>
    </list>
</property>

p:optimize 設置為 true,則表示使用 CGLib 動態代理技術。

通過這樣的配置之後,容器在創建 user 和 charger Bean 的實例時,就會自動為它們創建代理對象,而這一操作對於使用者來說完全是透明的 。

單元測試:

User user = (User) context.getBean("user");
Charger charger = (Charger) context.getBean("charger");

String userId = "001";
user.rent(userId);
charger.rent(userId);

輸出結果:

準備租賃的用戶 ID:001
User:租賃【充電寶】
準備租賃的用戶 ID:001
Charger:【充電寶】被租賃

3 DefaultAdvisorAutoProxyCreator

切面 Advisor 是切點和增強的復合體,而 DefaultAdvisorAutoProxyCreator 能夠掃描 Advisor, 並將 Advisor 自動織入到匹配的目標 Bean 中。

<bean id="user" class="net.deniro.spring4.aop.User"/>
<bean id="charger" class="net.deniro.spring4.aop.Charger"/>

<!-- 前置增強-->
<bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/>

<!-- 靜態正則表達式方法名匹配-->
<bean id="regexpAdvisor"
      class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
      p:advice-ref="rentBeforeAdvice">
    <!-- 匹配模式-->
    <property name="patterns">
        <list>
            <!-- 匹配字符串-->
            <value>.*rent.*</value>
        </list>
    </property>
</bean>

<!-- 使用 DefaultAdvisorAutoProxyCreator-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

首先我們配置了以靜態正則表達式方法名匹配的切面,然後直接配置了 DefaultAdvisorAutoProxyCreator Bean。

測試代碼與輸出結果與上一小節的 BeanNameAutoProxyCreator 相同。

JDK 動態代理是通過接口來實現方法攔截,所以必須確保要攔截的目標在接口中有定義。

CGLib 動態代理是通過動態生成代理子類來實現方法攔截,所以必須確保要攔截的目標方法可以被子類所訪問,也就是目標方法必須定義為非 final, 且非私有實例方法 。

Spring 中如何自動創建代理(spring中的三種自動代理創建器)