Spring 提供了自動代理機制,可讓容器自動生成代理,從而把開發人員從繁瑣的配置中解脫出來 。 具體是使用 BeanPostProcessor 來實現這項功能。正則表達式
這三種自動代理建立器 爲:BeanNameAutoProxyCreator , DefaultAdvisorAutoProxyCreator , AbstractAdvisorAutoProxyCreator。spring
BeanPostProcessor 代理建立器的實現類能夠分爲 3 類:單元測試
類型 | 實現類 |
---|---|
基於 Bean 配置名規則 | BeanNameAutoProxyCreator |
基於 Advisor 匹配規則 | DefaultAdvisorAutoProxyCreator |
基於 Bean 中的 AspectJ 註解標籤的匹配規則 | AnnotationAwareAspectJAutoProxyCreator |
BeanPostProcessor 類繼承關係測試
全部的自動代理器類都實現了 BeanPostPorcessor ,在容器實例化 Bean 時, BeanPostProcessor 將對它進行加工處理,因此自動代理建立器可以對知足匹配規則的 bean 自動建立代理對象。spa
假設有如下兩個實體類(用戶與充電寶)。代理
用戶類:code
public class User { public void rent(String userId) { System.out.println("User:租賃【充電寶】"); } public void back(String userId){ System.out.println("User:歸還【充電寶】"); } }
充電寶:regexp
public class Charger { public void rent(String userId) { System.out.println("Charger:【充電寶】被租賃"); } }
咱們但願經過 BeanNameAutoProxyCreator 經過 Bean 的名稱來自動建立代理,實現加強:xml
<?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:【充電寶】被租賃
切面 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, 且非私有實例方法 。