Spring AOP攔截-三種方式實(shí)現(xiàn)自動(dòng)代理詳解
這里的自動(dòng)代理,我講的是自動(dòng)代理bean對(duì)象,其實(shí)就是在xml中讓我們不用配置代理工廠,也就是不用配置class為org.springframework.aop.framework.ProxyFactoryBean的bean。
總結(jié)了一下自己目前所學(xué)的知識(shí)。
發(fā)現(xiàn)有三種方式實(shí)現(xiàn)自動(dòng)代理
用Spring一個(gè)自動(dòng)代理類DefaultAdvisorAutoProxyCreator:
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" data-filtered="filtered"></bean>
例如:
原來(lái)不用自動(dòng)代理的配置文件如下:
<!--?xml version="1.0" encoding="UTF-8"?--> <beans xmlns="https://www.springframework.org/schema/beans" xmlns:context="https://www.springframework.org/schema/context" xmlns:tx="https://www.springframework.org/schema/tx" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.3.xsd https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.3.xsd https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.3.xsd"> <!-- 代理前原對(duì)象 --> <bean class="cn.hncu.xmlImpl.Person" id="person"></bean> <!-- 切面 = 切點(diǎn)+通知 --> <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor"> <!-- 切點(diǎn) --> <property name="patterns"> <list> <value>.*run.*</value> </list> </property> <!-- 通知-由我們寫,實(shí)際代理動(dòng)作 --> <property name="advice"> <bean class="cn.hncu.xmlImpl.AroundAdvice" id="advice"></bean> </property> </bean> <!-- 代理工廠 --> <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="personProxied"> <!-- 放入原型對(duì)象 --> <property name="target" ref="person"></property> <!-- 放入切面 --> <property name="interceptorNames"> <list> <value>advisor</value> </list> </property> </bean> </beans>
現(xiàn)在改用自動(dòng)代理,如下配置:
<beans ...=""> <!-- 代理前原對(duì)象 --> <bean class="cn.hncu.xmlImpl.Person" id="person"></bean> <!-- 切面 = 切點(diǎn)+通知 --> <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor"> <!-- 切點(diǎn) --> <property name="patterns"> <list> <value>.*run.*</value> </list> </property> <!-- 通知-由我們寫,實(shí)際代理動(dòng)作 --> <property name="advice"> <bean class="cn.hncu.xmlImpl.AroundAdvice" id="advice"></bean> </property> </bean> <!-- 自動(dòng)代理 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean> </beans>
測(cè)試方法
@Test//自動(dòng)代理 public void demo4(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/xmlImpl/4.xml"); //我們直接在這里獲取Person對(duì)象就可以了,因?yàn)樵谧铋_始xml文件newPerson對(duì)象后,Spring就已經(jīng)幫我們代理了! Person p =ctx.getBean(Person.class); p.run(); p.say(); }
相對(duì)于前面,也就是把代理工廠部分換成自動(dòng)代理了。
演示結(jié)果:
自己寫一個(gè)自動(dòng)代理底層實(shí)現(xiàn):
我們也可以寫一個(gè)類,來(lái)實(shí)現(xiàn)DefaultAdvisorAutoProxyCreator自動(dòng)代理的功能!
首先,我們需要實(shí)現(xiàn)一個(gè)接口,也就是BeanPostProcessor接口。
BeanPostProcessor接口作用是:如果我們需要在Spring容器完成Bean的實(shí)例化、配置和其他的初始化前后添加一些自己的邏輯處理,我們就可以定義一個(gè)或者多個(gè)BeanPostProcessor接口的實(shí)現(xiàn),然后注冊(cè)到容器中。
而我們想要在原型對(duì)象bean被創(chuàng)建之后就代理了,就必須在原來(lái)的容器中拿到原來(lái)的原型對(duì)象,需要拿到原來(lái)spring容器中的切面對(duì)象,這個(gè)時(shí)候,我們就需要原來(lái)的容器,這個(gè)時(shí)候就需要另一個(gè)接口,也就是ApplicationContextAware接口!
通過(guò)這2個(gè)接口,我們就可以實(shí)現(xiàn)自動(dòng)代理了。
package cn.hncu.xmlImpl; import org.springframework.aop.Advisor; import org.springframework.aop.framework.ProxyFactoryBean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class MyAutoProxy implements BeanPostProcessor,ApplicationContextAware{ private ApplicationContext applicationContext=null; //bean創(chuàng)建之前調(diào)用 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean;//在這里,我們直接放行 } //bean創(chuàng)建之后調(diào)用 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { ProxyFactoryBean factory = new ProxyFactoryBean(); //把原型對(duì)象放入代理工廠 factory.setTarget(bean); //在這里 Advisor adv = applicationContext.getBean(Advisor.class); factory.addAdvisor(adv); //返回被代理后的對(duì)象 return factory.getObject(); } //拿到原來(lái)的spring中的容器 @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext=applicationContext; } }
5.xml
<beans...> <!-- 代理前原對(duì)象 --> <bean class="cn.hncu.xmlImpl.Person" id="person"></bean> <!-- 切面 = 切點(diǎn)+通知 --> <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor"> <!-- 切點(diǎn) --> <property name="patterns"> <list> <value>.*run.*</value> </list> </property> <!-- 通知-由我們寫,實(shí)際代理動(dòng)作 --> <property name="advice"> <bean class="cn.hncu.xmlImpl.AroundAdvice" id="advice"></bean> </property> </bean> <!-- 自己寫的自動(dòng)代理 --> <bean class="cn.hncu.xmlImpl.MyAutoProxy"></bean> </beans...>
測(cè)試方法:
@Test//自己實(shí)現(xiàn)的自動(dòng)代理 public void demo5(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/xmlImpl/5.xml"); Person p =ctx.getBean(Person.class); p.run(); p.say(); }
測(cè)試結(jié)果就不上圖了,和前面是一樣的。
其實(shí)很多時(shí)候,我們?nèi)绻约喝ゾ氁幌碌讓?,?duì)上層的框架更好理解。
還有一種方法。
使用aop標(biāo)簽配自動(dòng)代理
需要在beans加一個(gè)命名空間
xmlns:aop=https://www.springframework.org/schema/aop
還需要配xsi:schemaLocation,為aop加一個(gè)網(wǎng)絡(luò)地址。
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.3.xsd
我們需要一個(gè)aspectjweaver-jar包:
xml配置文件:
<!--?xml version="1.0" encoding="UTF-8"?--> <beans xmlns="https://www.springframework.org/schema/beans" xmlns:aop="https://www.springframework.org/schema/aop" xmlns:context="https://www.springframework.org/schema/context" xmlns:tx="https://www.springframework.org/schema/tx" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.3.xsd https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-4.3.xsd https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-4.3.xsd https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop-4.3.xsd "> <!-- 利用sop標(biāo)簽實(shí)現(xiàn)自動(dòng)代理 --> </aop:aspectj-autoproxy> <!-- 代理前原對(duì)象 --> <bean class="cn.hncu.xmlImpl.Person" id="person"></bean> <!-- 切面 = 切點(diǎn)+通知 --> <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor"> <!-- 切點(diǎn) --> <property name="patterns"> <list> <value>.*run.*</value> </list> </property> <!-- 通知-由我們寫,實(shí)際代理動(dòng)作 --> <property name="advice"> <bean class="cn.hncu.xmlImpl.AroundAdvice" id="advice"></bean> </property> </bean> </beans>
測(cè)試方法:
@Test//自動(dòng)代理 public void demo6(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/xmlImpl/6.xml"); Person p =ctx.getBean(Person.class); p.run(); p.say(); }
測(cè)試結(jié)果:
個(gè)人覺(jué)得能學(xué)會(huì)使用一種就OK了,不用全部記下來(lái),為了學(xué)習(xí),都了解一下就好,別人寫出來(lái),能看懂就好。
哈哈,其實(shí)底層學(xué)好了,自己寫的時(shí)候,就算不會(huì)用Spring的自動(dòng)代理,自己寫出來(lái)底層也是蠻好的嘛
總結(jié)
以上本文關(guān)于Spring AOP攔截-三種方式實(shí)現(xiàn)自動(dòng)代理詳解的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:快速理解Java設(shè)計(jì)模式中的組合模式、Java編程接口調(diào)用的作用及代碼分享、淺談Java實(shí)體對(duì)象的三種狀態(tài)以及轉(zhuǎn)換關(guān)系等,有什么問(wèn)題可以隨時(shí)留言,小編會(huì)及時(shí)回復(fù)大家的。感謝朋友們對(duì)本站的支持!
相關(guān)文章
Java8中Stream使用的一個(gè)注意事項(xiàng)
最近在工作中發(fā)現(xiàn)了對(duì)于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個(gè)非常重要的注意點(diǎn),所以這篇文章主要給大家介紹了關(guān)于Java8中Stream使用過(guò)程中的一個(gè)注意事項(xiàng),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-11-11Java 1.8使用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列
這篇文章主要為大家詳細(xì)介紹了Java 1.8使用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10SpringBoot實(shí)現(xiàn)本地文件存儲(chǔ)及預(yù)覽過(guò)程
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)本地文件存儲(chǔ)及預(yù)覽過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11java訪問(wèn)者模式的靜態(tài)動(dòng)態(tài)及偽動(dòng)態(tài)分派徹底理解
這篇文章主要為大家介紹了java訪問(wèn)者模式的靜態(tài)動(dòng)態(tài)及偽動(dòng)態(tài)分派徹底理解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-0630分鐘入門Java8之默認(rèn)方法和靜態(tài)接口方法學(xué)習(xí)
這篇文章主要介紹了30分鐘入門Java8之默認(rèn)方法和靜態(tài)接口方法學(xué)習(xí),詳細(xì)介紹了默認(rèn)方法和接口,有興趣的可以了解一下。2017-04-04在windows環(huán)境下安裝jdk8、jdk9、jdk11、jdk12并自由切換
這篇文章主要介紹了在windows環(huán)境下安裝jdk8、jdk9、jdk11、jdk12并自由切換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05Eclipse中如何引入JUnit進(jìn)行單元測(cè)試
這篇文章主要介紹了Eclipse中如何引入JUnit進(jìn)行單元測(cè)試問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04Java結(jié)合Kotlin實(shí)現(xiàn)寶寶年齡計(jì)算
這篇文章主要為大家介紹了Java結(jié)合Kotlin實(shí)現(xiàn)寶寶年齡計(jì)算示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06