一开瞭、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接口:
package com.ietree.spring.basic.aop.beforeadvice;public interface IService { void doFirst(); void doSecond();}
創(chuàng)建接口的實(shí)現(xiàn)類:
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()方法"); }}
創(chuàng)建前置通知類MyMethodBeforeAdvice,該類必須實(shí)現(xiàn)MethodBeforeAdvice接口:
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í)行前置通知..."); }}
配置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" 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>
測試:
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(); }}
輸出:
執(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()方法:
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); }}
配置文件:
<?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>
注意:后置通知可以獲取到目標(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接口:
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; }}
配置文件:
<?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>
測試:
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); }}
輸出:
執(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
注意:環(huán)繞通知不僅可以獲取到方法的返回結(jié)果励翼,而且還可以修改方法的返回結(jié)果粮揉。
(4)異常通知ThrowsAdvice
異常分兩種:1)運(yùn)行時異常,不進(jìn)行處理抚笔,也可以通過編譯扶认。若一個類繼承自RunTimeException,則該異常就是運(yùn)行時異常 2)編譯時異常殊橙,受查異常辐宾,Checked Exception。不進(jìn)行處理膨蛮,則無法通過編譯叠纹。若一個類繼承自Exception,則該異常就是受查異常敞葛。
創(chuàng)建接口IService:
package com.ietree.spring.basic.aop.throwsadvice;public interface IService { // 用戶登錄 boolean login(String username, String password) throws UserException;}
創(chuàng)建接口實(shí)現(xiàn)類SomeServiceImpl:
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; }}
創(chuàng)建三個自定義異常:
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); }}
用戶名異常:
package com.ietree.spring.basic.aop.throwsadvice;public class UsernameException extends UserException { public UsernameException() { super(); } public UsernameException(String message) { super(message); }}
密碼異常:
package com.ietree.spring.basic.aop.throwsadvice;public class PasswordException extends UserException { public PasswordException() { super(); } public PasswordException(String message) { super(message); }}
定義異常通知:
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()); }}
配置文件:
<?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>
測試:
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"); }}
(5)同時使用多個通知的配置方法
<?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>
三喳钟、顧問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)虐呻。
<?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>
2象泵、正則表達(dá)式匹配方法切入點(diǎn)顧問RegexpMethodPointcutAdvisor
RegexpMethodPointcutAdvisor,即正則表達(dá)式方法顧問斟叼。容器可根據(jù)正則表達(dá)式來設(shè)置切入點(diǎn)偶惠。注意,與正則表達(dá)式進(jìn)行匹配的對象是接口中的方法名朗涩,而非目標(biāo)類(接口實(shí)現(xiàn)類)的方法名忽孽。
<?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>
測試:
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(); }}
四、自動代理生成器
1、默認(rèn)advisor自動代理生成器
<?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>
測試:
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(); }}
注意:使用DefaultAdvisorAutoProxyCreator自動代理生成器會有以下幾個問題:
1)不能選擇目標(biāo)對象兄一。
2)不能選擇切面類型厘线,切面只能是advisor。
3)不能選擇advisor瘾腰,所有的advisor都將被作為切面織入到目標(biāo)方法中皆的。
需要解決這幾個問題覆履,需要使用Bean名稱自動代理生成器實(shí)現(xiàn)蹋盆。
2、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" 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>
五硝全、AspectJ對AOP的實(shí)現(xiàn)
1栖雾、AspectJ基本概念
AspectJ切入表達(dá)式原型:
execution( [modifiers-pattern] 訪問權(quán)限類型 ret-type-pattern 返回值類型 [declaring-type-pattern] 全限定性類名 name-pattern(param-pattern)方法名(參數(shù)名) [throws-pattern] 拋出異常類型 )
其中,帶有[ ]的部分是可以省略的伟众,紅色的部分是不能省略的部分析藕。
還可以使用以下符號:
符號
意義
0至多個任意字符
..
用在方法參數(shù)中,表示任意多個參數(shù)凳厢。
用在包名后账胧,表示當(dāng)前包及其子包路徑。
用在類名后先紫,表示當(dāng)前類及其子類治泥。
用在接口后,表示當(dāng)前接口及其實(shí)現(xiàn)類遮精。
2居夹、基于注解方式的實(shí)現(xiàn)
首先創(chuàng)建切面類 MyAspectJ:
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() { }}
配置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: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>
3、基于XML方式的實(shí)現(xiàn)
首先創(chuàng)建切面類 MyAspectJ:
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í)行最終通知方法"); }}
配置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: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>
程序輸出:
執(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