Spring 中如何自動創建代理(spring中的三種自動代理創建器)
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中的三種自動代理創建器)