詳解在Spring中如何自動(dòng)創(chuàng)建代理
Spring 提供了自動(dòng)代理機(jī)制,可以讓容器自動(dòng)生成代理,從而把開發(fā)人員從繁瑣的配置中解脫出來 。 具體是使用 BeanPostProcessor 來實(shí)現(xiàn)這項(xiàng)功能。
1 BeanPostProcessor
BeanPostProcessor 代理創(chuàng)建器的實(shí)現(xiàn)類可以分為 3 類:
類型 | 實(shí)現(xiàn)類 |
---|---|
基于 Bean 配置名規(guī)則 | BeanNameAutoProxyCreator |
基于 Advisor 匹配規(guī)則 | DefaultAdvisorAutoProxyCreator |
基于 Bean 中的 AspectJ 注解標(biāo)簽的匹配規(guī)則 | AnnotationAwareAspectJAutoProxyCreator |
BeanPostProcessor 類繼承關(guān)系
所有的自動(dòng)代理器類都實(shí)現(xiàn)了 BeanPostPorcessor ,在容器實(shí)例化 Bean 時(shí), BeanPostProcessor 將對它進(jìn)行加工處理,所以自動(dòng)代理創(chuàng)建器能夠?qū)M足匹配規(guī)則的 bean 自動(dòng)創(chuàng)建代理對象。
2 BeanNameAutoProxyCreator
假設(shè)有以下兩個(gè)實(shí)體類(用戶與充電寶)。
用戶類:
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 的名稱來自動(dòng)創(chuàng)建代理,實(shí)現(xiàn)增強(qiáng):
<?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"/> <!-- 前置增強(qiáng)--> <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 屬性允許指定一組需要自動(dòng)代理的 Bean 名稱, 這里可以使用 *
通配符 。
因?yàn)槲覀冃枰淼念惷謩e是 user 與 charger,都是以 er 結(jié)尾的,所以我們這里定義為 *er
。
也可以通過 beanNames 的 value 值來明確指定需要代理的 Bean 名稱,多個(gè)以逗號(hào)分隔(更常用)。
<!-- 指定自動(dòng)代理的 Bean 名稱--> <property name="beanNames" value="user,charger"> </property>
也可以通過 list 方式來指定 beanNames 的值:
<property name="beanNames"> <list> <value>user</value> <value>charger</value> </list> </property>
p:optimize 設(shè)置為 true,則表示使用 CGLib 動(dòng)態(tài)代理技術(shù)。
通過這樣的配置之后,容器在創(chuàng)建 user 和 charger Bean 的實(shí)例時(shí),就會(huì)自動(dòng)為它們創(chuàng)建代理對象,而這一操作對于使用者來說完全是透明的 。
單元測試:
User user = (User) context.getBean("user"); Charger charger = (Charger) context.getBean("charger"); String userId = "001"; user.rent(userId); charger.rent(userId);
輸出結(jié)果:
準(zhǔn)備租賃的用戶 ID:001
User:租賃【充電寶】
準(zhǔn)備租賃的用戶 ID:001
Charger:【充電寶】被租賃
3 DefaultAdvisorAutoProxyCreator
切面 Advisor 是切點(diǎn)和增強(qiáng)的復(fù)合體,而 DefaultAdvisorAutoProxyCreator 能夠掃描 Advisor, 并將 Advisor 自動(dòng)織入到匹配的目標(biāo) Bean 中。
<bean id="user" class="net.deniro.spring4.aop.User"/> <bean id="charger" class="net.deniro.spring4.aop.Charger"/> <!-- 前置增強(qiáng)--> <bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/> <!-- 靜態(tài)正則表達(dá)式方法名匹配--> <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"/>
首先我們配置了以靜態(tài)正則表達(dá)式方法名匹配的切面,然后直接配置了 DefaultAdvisorAutoProxyCreator Bean。
測試代碼與輸出結(jié)果與上一小節(jié)的 BeanNameAutoProxyCreator 相同。
JDK 動(dòng)態(tài)代理是通過接口來實(shí)現(xiàn)方法攔截,所以必須確保要攔截的目標(biāo)在接口中有定義。
CGLib 動(dòng)態(tài)代理是通過動(dòng)態(tài)生成代理子類來實(shí)現(xiàn)方法攔截,所以必須確保要攔截的目標(biāo)方法可以被子類所訪問,也就是目標(biāo)方法必須定義為非 final, 且非私有實(shí)例方法 。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
并發(fā)編程ConcurrentLinkedQueue示例詳解
這篇文章主要為大家介紹了并發(fā)編程ConcurrentLinkedQueue使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12java秒殺系統(tǒng)常見問題庫存超賣解決實(shí)例分析
這篇文章主要為大家介紹了java秒殺系統(tǒng)常見問題庫存超賣解決實(shí)例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11Spring?Boot配置內(nèi)容加密實(shí)現(xiàn)敏感信息保護(hù)
之前我們講過的配置相關(guān)知識(shí)都是Spring?Boot原生就提供的,而今天我們將介紹的功能并非Spring?Boot原生就支持,但卻非常有用:配置內(nèi)容的加密2021-11-11使用springboot不自動(dòng)初始化數(shù)據(jù)庫連接池
這篇文章主要介紹了使用springboot不自動(dòng)初始化數(shù)據(jù)庫連接池,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09