Spring與AOP

一开瞭、AOP概述
AOP(Aspect Orient Programming)录煤,面向切面編程捞稿,是面向?qū)ο缶幊蘋OP的一種補(bǔ)充身冀。面向?qū)ο缶幊淌菑撵o態(tài)角度考慮程序的結(jié)構(gòu),而面向切面編程是從動態(tài)角度考慮程序運(yùn)行過程括享。
AOP底層就是采用動態(tài)代理模式實(shí)現(xiàn)的搂根,采用了兩種代理:JDK的動態(tài)代理與CGLIB的動態(tài)代理。
面向切面編程铃辖,就是將交叉業(yè)務(wù)邏輯封裝成切面剩愧,利用AOP容器的功能將切面織入到主業(yè)務(wù)邏輯中。所謂交叉業(yè)務(wù)邏輯是指娇斩,通用的仁卷、與主業(yè)務(wù)邏輯無關(guān)的代碼。如安全檢查犬第、事務(wù)锦积、日志等。
若不是用AOP歉嗓,則會出現(xiàn)代碼糾纏丰介,即交叉業(yè)務(wù)邏輯與主業(yè)務(wù)邏輯混合在一起,這樣會使主業(yè)務(wù)邏輯變的混雜不清鉴分。
二哮幢、通知Advice
1、通知詳解
(1)前置通知MethodBeforeAdvice
定義前置通知志珍,需要實(shí)現(xiàn)MethodBeforeAdvice接口橙垢。該接口中有一個方法before(),會在目標(biāo)方法執(zhí)行之前執(zhí)行伦糯。
前置通知的特點(diǎn):
1柜某、在目標(biāo)方法執(zhí)行之前執(zhí)行。
2敛纲、不改變目標(biāo)方法的執(zhí)行流程喂击,前置通知代碼不能阻止目標(biāo)方法執(zhí)行。
3载慈、不改變目標(biāo)方法執(zhí)行的結(jié)果惭等。
舉例:
創(chuàng)建IService接口:


復(fù)制代碼

package com.ietree.spring.basic.aop.beforeadvice;public interface IService { void doFirst(); void doSecond();}


復(fù)制代碼

創(chuàng)建接口的實(shí)現(xiàn)類:


復(fù)制代碼

package com.ietree.spring.basic.aop.beforeadvice;public class SomeServiceImpl implements IService { @Override public void doFirst() { System.out.println("執(zhí)行doFirst()方法"); } @Override public void doSecond() { System.out.println("執(zhí)行doFirst()方法"); }}


復(fù)制代碼

創(chuàng)建前置通知類MyMethodBeforeAdvice,該類必須實(shí)現(xiàn)MethodBeforeAdvice接口:


復(fù)制代碼

package com.ietree.spring.basic.aop.beforeadvice;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;/** * 前置通知 * * @author Root */public class MyMethodBeforeAdvice implements MethodBeforeAdvice { // 當(dāng)前方法在目標(biāo)方法執(zhí)行之前執(zhí)行 // method:目標(biāo)方法 // args:目標(biāo)方法參數(shù)列表 // target:目標(biāo)對象 @Override public void before(Method method, Object[] args, Object target) throws Throwable { // 對于目標(biāo)方法的增強(qiáng)代碼就寫在這里 System.out.println("執(zhí)行前置通知..."); }}


復(fù)制代碼

配置XML文件:


復(fù)制代碼

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="someService" class="com.ietree.spring.basic.aop.beforeadvice.SomeServiceImpl"/> <bean id="myAdvice" class="com.ietree.spring.basic.aop.beforeadvice.MyMethodBeforeAdvice"/> <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"/> <property name="interceptorNames" value="myAdvice"/> </bean> </beans>


復(fù)制代碼

測試:

復(fù)制代碼

package com.ietree.spring.basic.aop.beforeadvice;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyTest { @Test public void test() { String resource = "com/ietree/spring/basic/aop/beforeadvice/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(resource); IService service = (IService)ac.getBean("serviceProxy"); service.doFirst(); System.out.println("=============="); service.doSecond(); }}
復(fù)制代碼

輸出:
執(zhí)行前置通知...執(zhí)行doFirst()方法==============執(zhí)行前置通知...執(zhí)行doFirst()方法

注意:執(zhí)行之前需要導(dǎo)入spring-aop-4.3.9.RELEASE.jar包
(2)后置通知AfterReturningAdvice
定義前置通知办铡,需要實(shí)現(xiàn)AfterReturningAdvice接口辞做。該接口中有一個方法afterReturning(),會在目標(biāo)方法執(zhí)行之后執(zhí)行寡具。
后置通知的特點(diǎn):
1秤茅、在目標(biāo)方法執(zhí)行之后執(zhí)行。
2童叠、不改變目標(biāo)方法的執(zhí)行流程框喳,后置通知代碼不能阻止目標(biāo)方法執(zhí)行。
3厦坛、不改變目標(biāo)方法執(zhí)行的結(jié)果五垮。
大致流程和前置通知差不多,這里就簡單列舉一下不同之處:
創(chuàng)建后置通知類并實(shí)現(xiàn)AfterReturningAdvice接口杜秸,重寫afterReturning()方法:


復(fù)制代碼

package com.ietree.spring.basic.aop.afterreturningadvice;import java.lang.reflect.Method;import org.springframework.aop.AfterReturningAdvice;/** * 后置通知:可以獲取到目標(biāo)方法的返回結(jié)果放仗,但是無法改變目標(biāo)方法的結(jié)果 * * @author Root */public class MyAfterReturningAdvice implements AfterReturningAdvice { // 在目標(biāo)方法執(zhí)行之后執(zhí)行 // returnValue:目標(biāo)方法的返回值 @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("執(zhí)行后置通知方法 returnValue = " + returnValue); }}


復(fù)制代碼

配置文件:


復(fù)制代碼

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="someService" class="com.ietree.spring.basic.aop.afterreturningadvice.SomeServiceImpl"/> <bean id="myAdvice" class="com.ietree.spring.basic.aop.afterreturningadvice.MyAfterReturningAdvice"/> <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"/> <property name="interceptorNames" value="myAdvice"/> </bean> </beans>


復(fù)制代碼

注意:后置通知可以獲取到目標(biāo)方法的返回結(jié)果,但是無法改變目標(biāo)方法執(zhí)行的返回結(jié)果撬碟。
(3)環(huán)繞通知MethodInterceptor
定義環(huán)繞通知诞挨,需要實(shí)現(xiàn)MethodInterceptor接口。環(huán)繞通知呢蛤,也叫方法攔截器惶傻,可以在目標(biāo)方法調(diào)用之前及之后做處理,可以改變目標(biāo)方法的返回值其障,也可以改變程序執(zhí)行流程银室。
創(chuàng)建環(huán)繞通知類MyMethodInterceptor,實(shí)現(xiàn)MethodInterceptor接口:


復(fù)制代碼

package com.ietree.spring.basic.aop.methodinterceptor;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;// 環(huán)繞通知:可以修改目標(biāo)方法的返回結(jié)果public class MyMethodInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("執(zhí)行環(huán)繞通知:目標(biāo)方法執(zhí)行之前"); // 執(zhí)行目標(biāo)方法 Object result = invocation.proceed(); System.out.println("執(zhí)行環(huán)繞通知:目標(biāo)方法執(zhí)行之后"); if(null != result) { result = ((String)result).toUpperCase(); } return result; }}


復(fù)制代碼

配置文件:


復(fù)制代碼

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="someService" class="com.ietree.spring.basic.aop.methodinterceptor.SomeServiceImpl"/> <bean id="myAdvice" class="com.ietree.spring.basic.aop.methodinterceptor.MyMethodInterceptor"/> <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"/> <property name="interceptorNames" value="myAdvice"/> </bean> </beans>


復(fù)制代碼

測試:

復(fù)制代碼

package com.ietree.spring.basic.aop.methodinterceptor;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyTest { @Test public void test() { String resource = "com/ietree/spring/basic/aop/methodinterceptor/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(resource); IService service = (IService)ac.getBean("serviceProxy"); service.doFirst(); System.out.println("=============="); String result = service.doSecond(); System.out.println(result); }}
復(fù)制代碼

輸出:


復(fù)制代碼

執(zhí)行環(huán)繞通知:目標(biāo)方法執(zhí)行之前執(zhí)行doFirst()方法執(zhí)行環(huán)繞通知:目標(biāo)方法執(zhí)行之后==============執(zhí)行環(huán)繞通知:目標(biāo)方法執(zhí)行之前執(zhí)行doSecond()方法執(zhí)行環(huán)繞通知:目標(biāo)方法執(zhí)行之后ABCDE


復(fù)制代碼

注意:環(huán)繞通知不僅可以獲取到方法的返回結(jié)果励翼,而且還可以修改方法的返回結(jié)果粮揉。
(4)異常通知ThrowsAdvice
異常分兩種:1)運(yùn)行時異常,不進(jìn)行處理抚笔,也可以通過編譯扶认。若一個類繼承自RunTimeException,則該異常就是運(yùn)行時異常 2)編譯時異常殊橙,受查異常辐宾,Checked Exception。不進(jìn)行處理膨蛮,則無法通過編譯叠纹。若一個類繼承自Exception,則該異常就是受查異常敞葛。
創(chuàng)建接口IService:


復(fù)制代碼

package com.ietree.spring.basic.aop.throwsadvice;public interface IService { // 用戶登錄 boolean login(String username, String password) throws UserException;}


復(fù)制代碼

創(chuàng)建接口實(shí)現(xiàn)類SomeServiceImpl:


復(fù)制代碼

package com.ietree.spring.basic.aop.throwsadvice;public class SomeServiceImpl implements IService { @Override public boolean login(String username, String password) throws UserException { if (!"jack".equals(username)) { throw new UsernameException("用戶名錯誤誉察!"); } if (!"123".equals(password)) { throw new PasswordException("密碼錯誤!"); }// double i = 3 / 0; return true; }}


復(fù)制代碼

創(chuàng)建三個自定義異常:


復(fù)制代碼

package com.ietree.spring.basic.aop.throwsadvice;/** * 自定義異常 * 異常分兩種: * 1)運(yùn)行時異常惹谐,不進(jìn)行處理持偏,也可以通過編譯驼卖。若一個類繼承自RunTimeException,則該異常就是運(yùn)行時異常 * 2)編譯時異常鸿秆,受查異常酌畜,Checked Exception。不進(jìn)行處理卿叽,則無法通過編譯桥胞。若一個類繼承自Exception,則該異常就是受查異常考婴。 * * @author Root */public class UserException extends Exception { public UserException() { super(); } public UserException(String message) { super(message); }}


復(fù)制代碼

用戶名異常:


復(fù)制代碼

package com.ietree.spring.basic.aop.throwsadvice;public class UsernameException extends UserException { public UsernameException() { super(); } public UsernameException(String message) { super(message); }}


復(fù)制代碼

密碼異常:


復(fù)制代碼

package com.ietree.spring.basic.aop.throwsadvice;public class PasswordException extends UserException { public PasswordException() { super(); } public PasswordException(String message) { super(message); }}


復(fù)制代碼

定義異常通知:


復(fù)制代碼

package com.ietree.spring.basic.aop.throwsadvice;import org.springframework.aop.ThrowsAdvice;/** * 異常通知 當(dāng)目標(biāo)方法拋出與指定類型的異常具有is-a關(guān)系的異常時,執(zhí)行當(dāng)前方法afterThrowing() * * @author Root */public class MyThrowsAdvice implements ThrowsAdvice { // 當(dāng)目標(biāo)方法拋出UsernameException異常時沥阱,執(zhí)行當(dāng)前方法 public void afterThrowing(UsernameException ex) { System.out.println("發(fā)生用戶名異常 ex = " + ex.getMessage()); } // 當(dāng)目標(biāo)方法拋出UsernameException異常時缎罢,執(zhí)行當(dāng)前方法 public void afterThrowing(PasswordException ex) { System.out.println("發(fā)生密碼異常 ex = " + ex.getMessage()); } // 當(dāng)目標(biāo)方法拋出UsernameException異常時,執(zhí)行當(dāng)前方法 public void afterThrowing(Exception ex) { System.out.println("發(fā)生其它異常 ex = " + ex.getMessage()); }}


復(fù)制代碼

配置文件:


復(fù)制代碼

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="someService" class="com.ietree.spring.basic.aop.throwsadvice.SomeServiceImpl"/> <bean id="myAdvice" class="com.ietree.spring.basic.aop.throwsadvice.MyThrowsAdvice"/> <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"/> <property name="interceptorNames" value="myAdvice"/> </bean> </beans>


復(fù)制代碼

測試:

復(fù)制代碼

package com.ietree.spring.basic.aop.throwsadvice;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyTest { @Test public void test() throws UserException { String resource = "com/ietree/spring/basic/aop/throwsadvice/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(resource); IService service = (IService)ac.getBean("serviceProxy"); service.login("jack", "123"); }}
復(fù)制代碼

(5)同時使用多個通知的配置方法


復(fù)制代碼

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="someService" class="com.ietree.spring.basic.aop.multipleadvice.SomeServiceImpl"/> <bean id="beforeAdvice" class="com.ietree.spring.basic.aop.multipleadvice.MyMethodBeforeAdvice"/> <bean id="afterAdvice" class="com.ietree.spring.basic.aop.multipleadvice.MyAfterReturningAdvice"/> <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"/> <property name="interceptorNames" value="beforeAdvice,afterAdvice"/> </bean> </beans>


復(fù)制代碼

三喳钟、顧問Advisor
通知(Advice)是Spring提供的一種切面(Aspect)屁使。但其功能過于簡單:只能將切面織入到目標(biāo)類的所有方法中,無法完成將切面織入到指定目標(biāo)方法中奔则。
顧問(Advisor)是Spring提供的另一種切面蛮寂。它可以完成更為復(fù)雜的切面織入功能。PointcutAdvisor是顧問的一種易茬,可以指定具體的切入點(diǎn)酬蹋。顧問將通知進(jìn)行了包裝,會根據(jù)不同的通知類型抽莱,在不同的時間點(diǎn)范抓,將切面織入到不同的切入點(diǎn)。
PointcutAdvisor接口有兩個較為常用的實(shí)現(xiàn)類:
NameMatchMethodPointcutAdvisor:名稱匹配方法切入點(diǎn)顧問
RegexpMethodPointcutAdvisor:正則表達(dá)式匹配方法切入點(diǎn)顧問
1食铐、名稱匹配方法切入點(diǎn)顧問NameMatchMethodPointcutAdvisor
NameMatchMethodPointcutAdvisor匕垫,即名稱匹配方法切入點(diǎn)顧問。容器可根據(jù)配置文件中指定的方法名來設(shè)置切入點(diǎn)虐呻。

復(fù)制代碼

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="someService" class="com.ietree.spring.basic.aop.advisor.namematchmethodpointcutadvisor.SomeServiceImpl"/> <bean id="myAdvice" class="com.ietree.spring.basic.aop.advisor.namematchmethodpointcutadvisor.MyMethodBeforeAdvice"/> <bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> <property name="advice" ref="myAdvice"/> <property name="mappedNames" value="ir"/> </bean> <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someService"/> <property name="interceptorNames" value="myAdvisor"/> </bean> </beans>
復(fù)制代碼

2象泵、正則表達(dá)式匹配方法切入點(diǎn)顧問RegexpMethodPointcutAdvisor
RegexpMethodPointcutAdvisor,即正則表達(dá)式方法顧問斟叼。容器可根據(jù)正則表達(dá)式來設(shè)置切入點(diǎn)偶惠。注意,與正則表達(dá)式進(jìn)行匹配的對象是接口中的方法名朗涩,而非目標(biāo)類(接口實(shí)現(xiàn)類)的方法名忽孽。


復(fù)制代碼

<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <bean id="someServiceImpl" class="com.ietree.spring.aop.advisor.SomeServiceImpl"></bean> <bean id="myAdvice" class="com.ietree.spring.aop.advisor.MyMethodBeforeAdvice"></bean> <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="myAdvice"></property> </bean> <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="someServiceImpl"/> <property name="interceptorNames" value="myAdvisor"/> </bean></beans>


復(fù)制代碼

測試:

復(fù)制代碼

package com.ietree.spring.aop.advisor;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * Created by Root on 2017/7/3. */public class Test { @org.junit.Test public void test01(){ String resource = "com/ietree/spring/aop/advisor/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(resource); ISomeService service = (ISomeService)ac.getBean("serviceProxy"); service.doFirst(); System.out.println("=========================="); service.doSecond(); System.out.println("=========================="); service.doThird(); }}
復(fù)制代碼

四、自動代理生成器
1、默認(rèn)advisor自動代理生成器


復(fù)制代碼

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="someServiceImpl" class="com.ietree.spring.aop.defaultadvisorautoproxycreator.SomeServiceImpl"></bean> <bean id="someServiceImpl2" class="com.ietree.spring.aop.defaultadvisorautoproxycreator.SomeServiceImpl"></bean> <bean id="myAdvice" class="com.ietree.spring.aop.defaultadvisorautoproxycreator.MyMethodBeforeAdvice"></bean> <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="myAdvice"></property> <property name="pattern" value=".*doFirst"/> </bean> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/></beans>


復(fù)制代碼

測試:

復(fù)制代碼

package com.ietree.spring.aop.defaultadvisorautoproxycreator;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * Created by Root on 2017/7/3. */public class Test { @org.junit.Test public void test01(){ String resource = "com/ietree/spring/aop/defaultadvisorautoproxycreator/applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(resource); ISomeService service = (ISomeService)ac.getBean("someServiceImpl"); service.doFirst(); System.out.println("=========================="); service.doSecond(); System.out.println("=========================="); service.doThird(); System.out.println("----------------------------------"); ISomeService service2 = (ISomeService)ac.getBean("someServiceImpl2"); service2.doFirst(); System.out.println("=========================="); service2.doSecond(); System.out.println("=========================="); service2.doThird(); }}
復(fù)制代碼

注意:使用DefaultAdvisorAutoProxyCreator自動代理生成器會有以下幾個問題:
1)不能選擇目標(biāo)對象兄一。
2)不能選擇切面類型厘线,切面只能是advisor。
3)不能選擇advisor瘾腰,所有的advisor都將被作為切面織入到目標(biāo)方法中皆的。
需要解決這幾個問題覆履,需要使用Bean名稱自動代理生成器實(shí)現(xiàn)蹋盆。
2、Bean名稱自動代理生成器


復(fù)制代碼

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="someService" class="com.ietree.spring.aop.defaultadvisorautoproxycreator.SomeServiceImpl"></bean> <bean id="someService2" class="com.ietree.spring.aop.defaultadvisorautoproxycreator.SomeServiceImpl"></bean> <bean id="myAdvice" class="com.ietree.spring.aop.defaultadvisorautoproxycreator.MyMethodBeforeAdvice"></bean> <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="myAdvice"></property> <property name="pattern" value=".*doFirst"/> </bean> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames" value="someService"/> <property name="interceptorNames" value="myAdvisor"/> </bean></beans>


復(fù)制代碼

五硝全、AspectJ對AOP的實(shí)現(xiàn)
1栖雾、AspectJ基本概念
AspectJ切入表達(dá)式原型:


復(fù)制代碼

execution( [modifiers-pattern] 訪問權(quán)限類型 ret-type-pattern 返回值類型 [declaring-type-pattern] 全限定性類名 name-pattern(param-pattern)方法名(參數(shù)名) [throws-pattern] 拋出異常類型 )


復(fù)制代碼

其中,帶有[ ]的部分是可以省略的伟众,紅色的部分是不能省略的部分析藕。
還可以使用以下符號:
符號
意義

0至多個任意字符

..
用在方法參數(shù)中,表示任意多個參數(shù)凳厢。
用在包名后账胧,表示當(dāng)前包及其子包路徑。

用在類名后先紫,表示當(dāng)前類及其子類治泥。
用在接口后,表示當(dāng)前接口及其實(shí)現(xiàn)類遮精。

2居夹、基于注解方式的實(shí)現(xiàn)
首先創(chuàng)建切面類 MyAspectJ:

復(fù)制代碼

package com.ietree.spring.aop.aspectj.annotation;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.;import org.springframework.util.StringUtils;import java.util.Locale;/* * 切面類 * <p> * Created by Root on 2017/7/5. /@Aspect // 表示當(dāng)前類為切面類public class MyAspectJ { // 設(shè)置前置通知 @Before("execution( ..ISomeService.doFirst(..))") public void before() { System.out.println("執(zhí)行前置通知方法..."); } @Before("execution( ..ISomeService.doFirst(..))") public void before(JoinPoint jp) { System.out.println("執(zhí)行前置通知方法,jp = " + jp); } // 設(shè)置后置通知 @AfterReturning("execution( ..ISomeService.doSecond(..))") public void afterReturning() { System.out.println("執(zhí)行后置通知方法..."); } @AfterReturning(value = "execution( ..ISomeService.doSecond(..))", returning = "result") public void afterReturning(Object result) { System.out.println("執(zhí)行后置通知方法本冲, result = " + result); } // 設(shè)置環(huán)繞通知 @Around("execution( ..ISomeService.doSecond(..))") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("執(zhí)行環(huán)繞通知方法之前..."); // 執(zhí)行目標(biāo)方法 Object result = pjp.proceed(); System.out.println("執(zhí)行環(huán)繞通知方法之后..."); if (!StringUtils.isEmpty(result)) { result = ((String) result).toUpperCase(Locale.US); } return result; } // 設(shè)置異常通知 @AfterThrowing("execution( ..ISomeService.doThird(..))") public void afterThrowing() { System.out.println("執(zhí)行異常通知方法..."); } // 設(shè)置異常通知 @AfterThrowing(value = "execution( ..ISomeService.doThird(..))", throwing = "ex") public void afterThrowing(Exception ex) { System.out.println("執(zhí)行異常通知方法准脂,ex = " + ex.getMessage()); } // 設(shè)置最終通知 //@After("doThirdPointCut()") @After("execution( ..ISomeService.doThird(..))") public void After() { System.out.println("執(zhí)行最終通知方法"); } // 定義一個切入點(diǎn),叫做doThirdPointCut()檬洞,可以用來替換掉同樣的切入點(diǎn)表達(dá)式狸膏,例如替換后的最終通知 @Pointcut("execution( *..ISomeService.doThird(..))") public void doThirdPointCut() { }}
復(fù)制代碼

配置XML:


復(fù)制代碼

<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="myService" class="com.ietree.spring.aop.aspectj.annotation.SomeServiceImpl"/> <bean id="myAspectJ" class="com.ietree.spring.aop.aspectj.annotation.MyAspectJ"/> <aop:aspectj-autoproxy/></beans>


復(fù)制代碼

3、基于XML方式的實(shí)現(xiàn)
首先創(chuàng)建切面類 MyAspectJ:

復(fù)制代碼

package com.ietree.spring.aop.aspectj.xml;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.;import org.springframework.util.StringUtils;import java.util.Locale;/* * 切面類 * <p> * Created by Root on 2017/7/5. */public class MyAspectJ { // 設(shè)置前置通知 public void before() { System.out.println("執(zhí)行前置通知方法..."); } public void before(JoinPoint jp) { System.out.println("執(zhí)行前置通知方法添怔,jp = " + jp); } // 設(shè)置后置通知 public void afterReturning() { System.out.println("執(zhí)行后置通知方法..."); } public void afterReturning(Object result) { System.out.println("執(zhí)行后置通知方法湾戳, result = " + result); } // 設(shè)置環(huán)繞通知 public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("執(zhí)行環(huán)繞通知方法之前..."); // 執(zhí)行目標(biāo)方法 Object result = pjp.proceed(); System.out.println("執(zhí)行環(huán)繞通知方法之后..."); if (!StringUtils.isEmpty(result)) { result = ((String) result).toUpperCase(Locale.US); } return result; } // 設(shè)置異常通知 public void afterThrowing() { System.out.println("執(zhí)行異常通知方法..."); } // 設(shè)置異常通知 public void afterThrowing(Exception ex) { System.out.println("執(zhí)行異常通知方法,ex = " + ex.getMessage()); } // 設(shè)置最終通知 public void after() { System.out.println("執(zhí)行最終通知方法"); }}
復(fù)制代碼

配置XML文件:

復(fù)制代碼

<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="myService" class="com.ietree.spring.aop.aspectj.xml.SomeServiceImpl"/> <bean id="myAspectJ" class="com.ietree.spring.aop.aspectj.xml.MyAspectJ"/> <aop:config> <aop:pointcut id="doFirstPointcut" expression="execution(* ..ISomeService.doFirst(..))"/> <aop:pointcut id="doSecondPointcut" expression="execution( ..ISomeService.doSecond(..))"/> <aop:pointcut id="doThirdPointcut" expression="execution( *..ISomeService.doThird(..))"/> <aop:aspect ref="myAspectJ"> <aop:before method="before" pointcut-ref="doFirstPointcut"/> <aop:before method="before(org.aspectj.lang.JoinPoint)" pointcut-ref="doFirstPointcut"/> <aop:after-returning method="afterReturning" pointcut-ref="doSecondPointcut"/> <aop:after-returning method="afterReturning(java.lang.Object)" pointcut-ref="doSecondPointcut" returning="result"/> <aop:around method="around" pointcut-ref="doSecondPointcut"/> <aop:after-throwing method="afterThrowing(java.lang.Exception)" pointcut-ref="doThirdPointcut" throwing="ex"/> <aop:after method="after" pointcut-ref="doThirdPointcut"/> </aop:aspect> </aop:config></beans>
復(fù)制代碼

程序輸出:


復(fù)制代碼

執(zhí)行前置通知方法...執(zhí)行前置通知方法澎灸,jp = execution(void com.ietree.spring.aop.aspectj.xml.ISomeService.doFirst())執(zhí)行doFirst()方法-----------------執(zhí)行環(huán)繞通知方法之前...執(zhí)行doSecond()方法執(zhí)行環(huán)繞通知方法之后...執(zhí)行后置通知方法院塞, result = ABCDE執(zhí)行后置通知方法...-----------------執(zhí)行最終通知方法執(zhí)行異常通知方法,ex = / by zerojava.lang.ArithmeticException: / by zero


復(fù)制代碼
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末性昭,一起剝皮案震驚了整個濱河市拦止,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖汹族,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萧求,死亡現(xiàn)場離奇詭異,居然都是意外死亡顶瞒,警方通過查閱死者的電腦和手機(jī)夸政,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來榴徐,“玉大人守问,你說我怎么就攤上這事】幼剩” “怎么了耗帕?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長袱贮。 經(jīng)常有香客問我仿便,道長,這世上最難降的妖魔是什么攒巍? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任嗽仪,我火速辦了婚禮,結(jié)果婚禮上柒莉,老公的妹妹穿的比我還像新娘闻坚。我一直安慰自己,他們只是感情好常柄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布鲤氢。 她就那樣靜靜地躺著,像睡著了一般西潘。 火紅的嫁衣襯著肌膚如雪卷玉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天喷市,我揣著相機(jī)與錄音相种,去河邊找鬼。 笑死品姓,一個胖子當(dāng)著我的面吹牛寝并,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播腹备,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼衬潦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了植酥?” 一聲冷哼從身側(cè)響起镀岛,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤弦牡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后漂羊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驾锰,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年走越,在試婚紗的時候發(fā)現(xiàn)自己被綠了椭豫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡旨指,死狀恐怖赏酥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情淤毛,我是刑警寧澤今缚,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布算柳,位于F島的核電站低淡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瞬项。R本人自食惡果不足惜蔗蹋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望囱淋。 院中可真熱鬧猪杭,春花似錦、人聲如沸妥衣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽税手。三九已至蜂筹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芦倒,已是汗流浹背艺挪。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兵扬,地道東北人麻裳。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像奸焙,于是被迫代替她去往敵國和親多糠。 傳聞我的和親對象是個殘疾皇子姻政,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)疆瑰,斷路器,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 本章內(nèi)容: 面向切面編程的基本原理 通過POJO創(chuàng)建切面 使用@AspectJ注解 為AspectJ切面注入依賴 ...
    謝隨安閱讀 3,149評論 0 9
  • 上一篇:Spring學(xué)習(xí)筆記(五禁漓、Bean裝配(下)) 一、AOP概念 1. 什么是AOP孵睬? AOP:Aspect...
    魯克巴克詩閱讀 1,724評論 0 2
  • **** AOP 面向切面編程 底層原理 代理2ゼ摺!掰读! 今天AOP課程1秘狞、 Spring 傳統(tǒng) AOP2、 Spri...
    luweicheng24閱讀 1,369評論 0 1
  • 同一棟樓蹈集,三個時代烁试,三個故事,三個結(jié)局拢肆。如果墻會說話减响,你希望聽到什么? 安真和芝蘭是上下樓的好朋友郭怪。父親因病去世后...
    scmsuki閱讀 423評論 0 0