AOP通知
java
Spring中經常使用的AOP通知有五種:spring
前置通知:在某方法調用以前執行;
app
後置通知:在後方法調用以後執行;less
異常通知:在某方法發生異常時執行;ide
返回通知:在某方法進行返回時執行;函數
環繞通知:可手動進行控制以上四種通知的執行;測試
AOP配置
spa
加入一下spring的jar包:.net
配置文件中引入xmlns:aop,加入<aop:aspectj-autoproxy></aop:aspectj-autoproxy>,具體配置以下:代理
<?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:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd "> <context:component-scan base-package="cn.net.bysoft.lesson7"> </context:component-scan> <!-- 自動生成aop代理 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
接下來編寫測試類與切面類,作一個簡單的接口,其中有4個方法,有是加減乘除四個函數,需求是在執行這4個函數的時候進行日誌輸入:
package cn.net.bysoft.lesson7; public interface Arithmentic { int add(int i, int j); int sub(int i, int j); int mul(int i, int j); int div(int i, int j); }
package cn.net.bysoft.lesson7; import org.springframework.stereotype.Component; @Component() public class ArithmenticImpl implements Arithmentic { @Override public int add(int i, int j) { return i + j; } @Override public int sub(int i, int j) { return i - j; } @Override public int mul(int i, int j) { return i * j; } @Override public int div(int i, int j) { return i * j; } }
前置通知
編寫一個日誌切面類,提供前置通知:
package cn.net.bysoft.lesson7; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class LoggingAspect { // 調用前 @Before("execution(public int cn.net.bysoft.lesson7.Arithmentic.*(int, int))") public void beforeMethod(JoinPoint joinPoint) { System.out.println("The method " + joinPoint.getSignature().getName() + " begins with" + Arrays.asList(joinPoint.getArgs())); } }
其中beforeMethod使用@Before裝飾,表明前置通知,在方法調用以前執行,@Before的參數是表明對cn.net.bysoft.lesson7這個包中的Arithmentic類的全部方法進行前置通知。
參數JoinPoint是切面的鏈接點,能夠得到執行的方法的信息,如名稱和參數值等,在前置通知時得到不到返回值,由於Arithmentic的方法還未執行。
編寫測試類:
package cn.net.bysoft.lesson7; import org.junit.Before; import org.junit.Test; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Lesson7Test { private AbstractApplicationContext ctx; @Before public void initApplicationContext() { // 建立Spring容器 ctx = new ClassPathXmlApplicationContext( "applicationContext-lesson7.xml"); } @Test public void test(){ Arithmentic arithmentic = ctx.getBean(Arithmentic.class); int result = arithmentic.add(3, 6); System.out.println(result); ctx.close(); } }
後置通知
加入後置通知,使用@After修飾方法,後置通知表示不管調用的方法是否異常,都會執行:
// 調用後,不管是否異常 @After("execution(public int cn.net.bysoft.lesson7.Arithmentic.*(int, int))") public void afterMethod(JoinPoint joinPoint) { System.out.println("The method " + joinPoint.getSignature().getName() + " begins with" + Arrays.asList(joinPoint.getArgs())); }
@Test public void testAfter(){ Arithmentic arithmentic = ctx.getBean(Arithmentic.class); int result = arithmentic.div(3, 6); System.out.println(result); ctx.close(); }
進行測試,是否若是方法發生異常,也會執行後置通知,將除數設置爲0:
異常通知
若方法如上面的代碼會發生異常,也能夠進行通知。使用@AfterThrowing修飾方法,value等於要調用的方法,throwing等於異常,以下:
@AfterThrowing(value = "execution(public int cn.net.bysoft.lesson7.Arithmentic.*(int, int))", throwing = "ex") public void exceptionMethod(JoinPoint joinPoint, Exception ex) { System.out.println("The method " + joinPoint.getSignature().getName() + " exception: " + ex); }
返回通知
當方法執行成功,沒有發生異常,並返回結果,可使用返回通知進行日誌輸出。使用@AfterReturning修飾方法,value等於要進行切面的方法,returing等於返回值,以下:
// 返回通知 @AfterReturning(value = "execution(public int cn.net.bysoft.lesson7.Arithmentic.*(int, int))", returning = "result") public void returnMethod(JoinPoint joinPoint, Object result) { System.out.println("The method " + joinPoint.getSignature().getName() + " returning: " + result); }
環繞通知
環繞通知功能很強大,能夠將上面的幾種通知進行自定義控制,它至關於咱們編寫的動態代理,使用@Around對方法進行修飾,傳遞一個ProceedingJoinPoint方法,能夠決定是否決定執行目標方法,而且環繞通知必須有返回值,該返回值即爲目標方法的返回值。代碼以下:
// 環繞通知 @Around("execution(public int cn.net.bysoft.lesson7.Arithmentic.*(int, int))") public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){ System.out.println("aroundMethod"); return 100; }
爲了區分環繞通知與以前的通知,現將以前的通知代碼註釋掉:
結果爲100,今後處能夠看出環繞通知功能很是強大,接下來,完成環繞通知的代碼,調用參數proceedingJoinPoint對象的proceed方法,能夠執行目標方法,並得到返回值,並在該方法以前、以後、異常和返回時加入想要的通知:
// 環繞通知 @Around("execution(public int cn.net.bysoft.lesson7.Arithmentic.*(int, int))") public Object aroundMethod(ProceedingJoinPoint proceedingJoinPoint){ Object result = null; String methodName = proceedingJoinPoint.getSignature().getName(); try { // 前置通知。 System.out.println("after " + methodName); result = proceedingJoinPoint.proceed(); // 返回通知。 System.out.println("returing " + methodName); } catch (Throwable e) { // 異常通知。 System.out.println("exception " + e); throw new RuntimeException(e); } // 後置通知。 System.out.println("afte " + methodName); return result; }
測試一下,執行目標方法,不帶有異常,結果以下:
在測試一個目標方法發生異常的狀況:
以上,就是spring經常使用的5種aop通知。
切面的優先級
若是有多個切面類,好比一個用來輸出日誌,一個用來驗證參數是否合法,還有一些其餘的……如何設置切面的優先級,好比驗證參數的切面類要在輸出日誌的切面類以前執行,具體來看代碼,編寫一個驗證切面類:
package cn.net.bysoft.lesson7; import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class ValidationAspect { @Before("execution(public int cn.net.bysoft.lesson7.Arithmentic.*(int, int))") public void beforeMethod(JoinPoint joinPoint) { System.out.println("validate args" + joinPoint.getSignature().getName() + " begins with" + Arrays.asList(joinPoint.getArgs())); } }
進行測試:
目前日誌切面類在驗證切面類以前執行,可使用@Order對切面類進行修飾,輸入須要進行排序:
@Order(1) public class ValidationAspect {
@Order(2) public class LoggingAspect {
再一次進行測試:
以上就是spring的aop的簡單使用。