Spring框架建議您在基于Spring 1.2舊樣式dtd的AOP實(shí)現(xiàn)上使用 Spring AspectJ AOP實(shí)現(xiàn)易于使用。
有兩種使用Spring AOP AspectJ實(shí)現(xiàn)的方法:
通過注釋: 我們將在這里學(xué)習(xí)。 通過xml配置(基于模式): 我們將在下一頁中學(xué)習(xí)它。
Spring AspectJ AOP實(shí)現(xiàn)提供了許多注釋:
@Aspect 將該類聲明為方面。 @Pointcut 聲明切入點(diǎn)表達(dá)式。
用于創(chuàng)建建議的注釋如下:
@Before 聲明before建議。在調(diào)用實(shí)際方法之前將其應(yīng)用。 @After 聲明after建議。在調(diào)用實(shí)際方法之后并返回結(jié)果之前應(yīng)用。 @AfterReturning 聲明返回建議之后。在調(diào)用實(shí)際方法之后并返回結(jié)果之前應(yīng)用。但是您可以在建議中獲得結(jié)果值。 @Around 聲明環(huán)繞建議。它在調(diào)用實(shí)際方法之前和之后應(yīng)用。 @AfterThrowing 聲明了throws建議。如果實(shí)際方法引發(fā)異常,則應(yīng)用此方法。
切入點(diǎn)是Spring AOP的一種表達(dá)語言。
@Pointcut >注釋用于定義切入點(diǎn)。我們也可以通過名稱引用切入點(diǎn)表達(dá)式。讓我們看一下切入點(diǎn)表達(dá)式的簡單示例。
@Pointcut("execution(* Operation.*(..))") private void doSomething() {}
切入點(diǎn)表達(dá)式的名稱為doSomething()。不管返回類型如何,它將應(yīng)用于所有Operation類的方法。
讓我們嘗試通過以下示例了解切入點(diǎn)表達(dá)式:
@Pointcut("execution(public * *(..))")
它將應(yīng)用于所有公共方法。
@Pointcut("execution(public Operation.*(..))")
它將應(yīng)用于Operation類的所有公共方法。
@Pointcut("execution(* Operation.*(..))")
它將應(yīng)用于Operation類的所有方法。
@Pointcut("execution(public Employee.set*(..))")
它將應(yīng)用于Employee類的所有公共設(shè)置方法。
@Pointcut("execution(int Operation.*(..))")
它將應(yīng)用于所有返回int值的Operation類方法。
在實(shí)際業(yè)務(wù)邏輯方法之前應(yīng)用AspectJ Before Advice。您可以在此處執(zhí)行任何操作,例如轉(zhuǎn)換,身份驗(yàn)證等。
創(chuàng)建一個(gè)包含實(shí)際業(yè)務(wù)邏輯的類。
文件: Operation.java
package com.nhooo; public class Operation{ public void msg(){System.out.println("msg method invoked");} public int m(){System.out.println("m method invoked");return 2;} public int k(){System.out.println("k method invoked");return 3;} }
現(xiàn)在,創(chuàng)建包含在建議之前的方面類。
文件: TrackOperation.java
package com.nhooo; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class TrackOperation{ @Pointcut("execution(* Operation.*(..))") public void k(){}//pointcut name @Before("k()")//在before通知上應(yīng)用切入點(diǎn) public void myadvice(JoinPoint jp)//it is advice (before advice) { System.out.println("additional concern"); //System.out.println("Method Signature: " + jp.getSignature()); } }
現(xiàn)在創(chuàng)建定義bean的applicationContext.xml文件。
文件: applicationContext.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="opBean" class="com.nhooo.Operation"> </bean> <bean id="trackMyBean" class="com.nhooo.TrackOperation"></bean> <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"></bean> </beans>
現(xiàn)在,讓我們稱為實(shí)際方法。
文件: Test.java
package com.nhooo; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test{ public static void main(String[] args){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Operation e = (Operation) context.getBean("opBean"); System.out.println("calling msg..."); e.msg(); System.out.println("calling m..."); e.m(); System.out.println("calling k..."); e.k(); } }
輸出
calling msg... additional concern msg() method invoked calling m... additional concern m() method invoked calling k... additional concern k() method invoked
正如您看到的,在調(diào)用msg(),m()和k()方法之前,還會(huì)顯示其他問題。
現(xiàn)在,如果您按如下所示更改切入點(diǎn)表達(dá)式:
@Pointcut("execution(* Operation.m*(..))")
現(xiàn)在,將更加關(guān)注Operation類中以m開頭的方法。輸出將如下所示:
calling msg... additional concern msg() method invoked calling m... additional concern m() method invoked calling k... k() method invoked
現(xiàn)在您可以看到在調(diào)用k()方法之前未打印其他問題。
在調(diào)用實(shí)際的業(yè)務(wù)邏輯方法之后,應(yīng)用了after建議之后的AspectJ。它可以用來維護(hù)日志,安全性,通知等。
在這里,我們假設(shè) Operation.java , applicationContext.xml 和 Test.java 文件與@Before示例中給出的文件相同。
package com.nhooo; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Pointcut; @Aspect public class TrackOperation{ @Pointcut("execution(* Operation.*(..))") public void k(){}//pointcut name @After("k()")//applying pointcut on after advice public void myadvice(JoinPoint jp)//it is advice (after advice) { System.out.println("additional concern"); //System.out.println("Method Signature: " + jp.getSignature()); } }
輸出
calling msg... msg() method invoked additional concern calling m... m() method invoked additional concern calling k... k() method invoked additional concern
您可以看到在調(diào)用msg(),m()和k()方法之后,還會(huì)出現(xiàn)其他問題。
通過在返回建議后使用,我們可以在建議中獲得結(jié)果。
創(chuàng)建包含以下內(nèi)容的類業(yè)務(wù)邏輯。
文件: Operation.java
package com.nhooo; public class Operation{ public int m(){System.out.println("m() method invoked");return 2;} public int k(){System.out.println("k() method invoked");return 3;} }
創(chuàng)建返回建議后包含的方面類。
文件: TrackOperation.java
package com.nhooo; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; @Aspect public class TrackOperation{ @AfterReturning( pointcut = "execution(* Operation.*(..))", returning= "result") public void myadvice(JoinPoint jp,Object result)//it is advice (after returning advice) { System.out.println("additional concern"); System.out.println("Method Signature: " + jp.getSignature()); System.out.println("Result in advice: "+result); System.out.println("end of after returning advice..."); } }
文件: applicationContext.xml
與@Before建議示例中給出的
文件: Test.java
現(xiàn)在創(chuàng)建調(diào)用實(shí)際方法的Test類。
package com.nhooo; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test{ public static void main(String[] args){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Operation e = (Operation) context.getBean("opBean"); System.out.println("calling m..."); System.out.println(e.m()); System.out.println("calling k..."); System.out.println(e.k()); } }
輸出
calling m... m() method invoked additional concern Method Signature: int com.nhooo.Operation.m() Result in advice: 2 end of after returning advice... 2 calling k... k() method invoked additional concern Method Signature: int com.nhooo.Operation.k() Result in advice: 3 end of after returning advice... 3
您可以看到返回值已打印兩次,一次是由TrackOperation類打印,第二次是Test類。
圍繞通知的AspectJ在調(diào)用實(shí)際的業(yè)務(wù)邏輯方法之前和之后都得到應(yīng)用。
在這里,我們是假設(shè) applicationContext.xml 文件與@Before示例中給出的文件相同。
創(chuàng)建一個(gè)包含實(shí)際業(yè)務(wù)邏輯的類。
文件: Operation.java
package com.nhooo; public class Operation{ public void msg(){System.out.println("msg() is invoked");} public void display(){System.out.println("display() is invoked");} }
創(chuàng)建包含圍繞建議的方面類。
您需要在advice方法中傳遞 PreceedingJoinPoint 引用,以便我們可以通過調(diào)用proce來進(jìn)行請求()方法。
文件: TrackOperation.java
package com.nhooo; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; @Aspect public class TrackOperation { @Pointcut("execution(* Operation.*(..))") public void abcPointcut(){} @Around("abcPointcut()") public Object myadvice(ProceedingJoinPoint pjp) throws Throwable { System.out.println("Additional Concern Before calling actual method"); Object obj=pjp.proceed(); System.out.println("Additional Concern After calling actual method"); return obj; } }
文件: Test.java
現(xiàn)在創(chuàng)建調(diào)用實(shí)際方法的Test類。
package com.nhooo; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test{ public static void main(String[] args){ ApplicationContext context = new classPathXmlApplicationContext("applicationContext.xml"); Operation op = (Operation) context.getBean("opBean"); op.msg(); op.display(); } }
輸出
Additional Concern Before calling actual method msg() is invoked Additional Concern After calling actual method Additional Concern Before calling actual method display() is invoked Additional Concern After calling actual method
您可以看到在調(diào)用msg()和顯示方法之前和之后,還會(huì)打印出其他問題。
通過使用after throw建議,我們可以在TrackOperation類中打印異常。讓我們看一下AspectJ AfterThrowing建議的示例。
創(chuàng)建包含業(yè)務(wù)邏輯的類。
文件: Operation.java
package com.nhooo; public class Operation{ public void validate(int age)throws Exception{ if(age<18){ throw new ArithmeticException("Not valid age"); } else{ System.out.println("Thanks for vote"); } } }
創(chuàng)建在拋出建議后包含的方面類。
在這里,我們還需要傳遞Throwable引用,以便我們可以在此處攔截異常。
文件: TrackOperation.java
package com.nhooo; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; @Aspect public class TrackOperation{ @AfterThrowing( pointcut = "execution(* Operation.*(..))", throwing= "error") public void myadvice(JoinPoint jp,Throwable error)//it is advice { System.out.println("additional concern"); System.out.println("Method Signature: " + jp.getSignature()); System.out.println("Exception is: "+error); System.out.println("end of after throwing advice..."); } }
文件: applicationContext.xml
與@Before建議示例中給出的
文件: Test.java
現(xiàn)在創(chuàng)建調(diào)用實(shí)際方法的Test類。
package com.nhooo; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test{ public static void main(String[] args){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Operation op = (Operation) context.getBean("opBean"); System.out.println("calling validate..."); try{ op.validate(19); }catch(Exception e){System.out.println(e);} System.out.println("calling validate again..."); try{ op.validate(11); }catch(Exception e){System.out.println(e);} } }
輸出
calling validate... Thanks for vote calling validate again... additional concern Method Signature: void com.nhooo.Operation.validate(int) Exception is: java.lang.ArithmeticException: Not valid age end of after throwing advice... java.lang.ArithmeticException: Not valid age