本文講述使用AspectJ框架實現Spring AOP。java
再重複一下Spring AOP中的三個概念,spring
AspectJ是基於註釋(Annotation)的,因此須要JDK5.0以上的支持。express
AspectJ支持的註釋類型以下:app
首先定義一個簡單的bean,CustomerBo實現了接口ICustomerBo框架
ICustomerBo.java以下:測試
package com.lei.demo.aop.aspectj; public interface ICustomerBo { void addCustomer(); void deleteCustomer(); String AddCustomerReturnValue(); void addCustomerThrowException() throws Exception; void addCustomerAround(String name); }
CustomerBo.java以下:this
package com.lei.demo.aop.aspectj; public class CustomerBo implements ICustomerBo { public void addCustomer() { System.out.println("addCustomer() is running ..."); } public void deleteCustomer() { System.out.println("deleteCustomer() is running ..."); } public String AddCustomerReturnValue() { System.out.println("AddCustomerReturnValue() is running ..."); return "abc"; } public void addCustomerThrowException() throws Exception { System.out.println("addCustomerThrowException() is running ..."); throw new Exception("Generic Error"); } public void addCustomerAround(String name) { System.out.println("addCustomerAround() is running ,args:"+name); } }
首先沒有引入Pointcut以前,Advice和Pointcut是混在一塊兒的spa
步驟,只須要兩步,以下:code
第一步,建立Aspect類orm
LoggingAspect.java以下:
package com.lei.demo.aop.aspectj; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class LoggingAspect { @Before("execution(public * com.lei.demo.aop.aspectj.CustomerBo.addCustomer(..))") public void logBefore(JoinPoint joinPoint){ System.out.println("logBefore() is running ..."); System.out.println("hijacked:"+joinPoint.getSignature().getName()); System.out.println("**********"); } @After("execution(public * com.lei.demo.aop.aspectj.CustomerBo.deleteCustomer(..))") public void logAfter(JoinPoint joinPoint){ System.out.println("logAfter() is running ..."); System.out.println("hijacked:"+joinPoint.getSignature().getName()); System.out.println("**********"); } }
解釋:
1. 必須使用@Aspect在LoggingAspect聲明以前註釋,以便被框架掃描到
2. 此例Advice和Pointcut結合在一塊兒,類中的具體方法logBefore和logAfter即爲Advice,是要注入的代碼,Advice方法上的表達式爲Pointcut表達式,即定義了切入點,上例中@Before註釋的表達式表明執行CustomerBo.addCustomer方法時注入logBefore代碼。
3. 在LoggingAspect方法上加入@Before或者@After等註釋
4. "execution(public * com.lei.demo.aop.aspectj.CustomerBo.addCustomer(..))"是Aspect的切入點表達式,其中,*表明返回類型,後邊的就要定義要攔截的方法名,這裏寫的的是com.lei.demo.aop.aspectj.CustomerBo.addCustomer表示攔截CustomerBo中的addCustomer方法,(..)表明參數匹配,此處表示匹配任意數量的參數,能夠是0個也能夠是多個,若是你肯定這個方法不須要使用參數能夠直接用(),還可使用(*)來匹配一個任意類型的參數,還可使用 (* , String),這樣表明匹配兩個參數,第二個參數必須是String 類型的參數
5. AspectJ表達式,能夠對整個包定義,例如,execution(* com.lei.service..*.*(..))表示切入點是com.lei.sevice包中的任意一個類的任意方法,具體的表達式請自行百度。
第二步,配置Spring配置文件,
配置Spring-AOP-AspectJ.xml文件,以下:
<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-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <aop:aspectj-autoproxy/> <bean id="customerBo" class="com.lei.demo.aop.aspectj.CustomerBo"/> <bean id="logAspect" class="com.lei.demo.aop.aspectj.LoggingAspect" /> </beans>
解釋:
1. <aop:aspectj-autoproxy/>啓動AspectJ支持,這樣Spring會自動尋找用@Aspect註釋過的類,其餘的配置與spring普通bean配置同樣。
測試:
執行App.java以下:
package com.lei.demo.aop.aspectj; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { ApplicationContext appContext = new ClassPathXmlApplicationContext( new String[] { "Spring-AOP-AspectJ.xml" }); ICustomerBo customer=(ICustomerBo)appContext.getBean("customerBo"); customer.addCustomer(); System.out.println("-------------------------------------------"); customer.deleteCustomer(); } }
結果:
logBefore() is running ...
hijacked:addCustomer
**********
addCustomer() is running ...
-------------------------------------------
deleteCustomer() is running ...
logAfter() is running ...
hijacked:deleteCustomer
**********
須要三步,
第一步,PointcutsDefinition.java定義了Pointcut,以下:
package com.lei.demo.aop.aspectj; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; @Aspect public class PointcutsDefinition { @Pointcut("execution(* com.lei.demo.aop.aspectj.CustomerBo.*(..))") public void customerLog() { } }
解釋:
1. 類聲明前加入@Aspect註釋,以便被框架掃描到。
2. @Pointcut是切入點聲明,指定須要注入的代碼的位置,如上例中指定切入點爲CustomerBo類中的全部方法,在實際業務中每每是指定切入點到一個邏輯層,例如 execution (* com.lei.business.service.*.*(..)),表示aop切入點爲service包中全部類的全部方法,具體的表達式後邊會有介紹。
3. 方法customerLog是一個簽名,在Advice中能夠用此簽名代替切入點表達式,因此不須要在方法體內編寫實際代碼,只起到助記功能,例如此處表明操做CustomerBo類時須要的切入點。
第二步,建立Advice類
LoggingAspect.java以下:
package com.lei.demo.aop.aspectj; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class LoggingAspect { @Before("com.lei.demo.aop.aspectj.PointcutsDefinition.customerLog()") public void logBefore(JoinPoint joinPoint){ System.out.println("logBefore() is running ..."); System.out.println("hijacked:"+joinPoint.getSignature().getName()); System.out.println("**********"); } @After("com.lei.demo.aop.aspectj.PointcutsDefinition.customerLog()") public void logAfter(JoinPoint joinPoint){ System.out.println("logAfter() is running ..."); System.out.println("hijacked:"+joinPoint.getSignature().getName()); System.out.println("**********"); } }
註釋:
1. @Before和@After使用PointcutsDefinition中的方法簽名代替Pointcut表達式找到相應的切入點,即經過簽名找到PointcutsDefinition中customerLog簽名上的Pointcut表達式,表達式指定切入點爲CustomerBo類中的全部方法。因此此例中Advice類LoggingAdvice,爲CustomerBo中的全部方法都加入了@Before和@After兩種類型的兩種操做。
2. 對於PointcutsDefinition來講,主要職責是定義Pointcut,能夠在其中第一多個切入點,而且能夠用便於記憶的方法簽名進行定義。
3. 單獨定義Pointcut的好處是,一是經過使用有意義的方法名,而不是難讀的Pointcut表達式,使代碼更加直觀;二是Pointcut能夠實現共享,被多個Advice直接調用。如有多個Advice調用某個Pointcut,而這個Pointcut的表達式在未來有改變時,只需修改一個地方,維護更加方便。
第三步,配置Spring配置文件,配置文件並無改變
配置Spring-AOP-AspectJ.xml文件,以下:
<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-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <aop:aspectj-autoproxy/> <bean id="customerBo" class="com.lei.demo.aop.aspectj.CustomerBo"/> <bean id="logAspect" class="com.lei.demo.aop.aspectj.LoggingAspect" /> </beans>
App.java不變,運行測試代碼App.java
輸出結果:
logBefore() is running ...
hijacked:addCustomer
**********
addCustomer() is running ...
logAfter() is running ...
hijacked:addCustomer
**********
-------------------------------------------
logBefore() is running ...
hijacked:deleteCustomer
**********
deleteCustomer() is running ...
logAfter() is running ...
hijacked:deleteCustomer
**********
Spring3.0.5幫助文檔中的切入點表達式以下:
Some examples of common pointcut expressions are given below.
the execution of any public method:
execution(public * *(..))
the execution of any method with a name beginning with "set":
execution(* set*(..))
the execution of any method defined by the AccountService interface:
execution(* com.xyz.service.AccountService.*(..))
the execution of any method defined in the service package:
execution(* com.xyz.service.*.*(..))
the execution of any method defined in the service package or a sub-package:
execution(* com.xyz.service..*.*(..))
any join point (method execution only in Spring AOP) within the service package:
within(com.xyz.service.*)
any join point (method execution only in Spring AOP) within the service package or a sub-package:
within(com.xyz.service..*)
any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:
this(com.xyz.service.AccountService)
'this' is more commonly used in a binding form :- see the following section on advice for how to make the proxy object available in the advice body.
any join point (method execution only in Spring AOP) where the target object implements the AccountService interface:
target(com.xyz.service.AccountService)
'target' is more commonly used in a binding form :- see the following section on advice for how to make the target object available in the advice body.
any join point (method execution only in Spring AOP) which takes a single parameter, and where the argument passed at runtime is Serializable:
args(java.io.Serializable)
'args' is more commonly used in a binding form :- see the following section on advice for how to make the method arguments available in the advice body.
Note that the pointcut given in this example is different to execution(* *(java.io.Serializable)): the args version matches if the argument passed at runtime is Serializable, the execution version matches if the method signature declares a single parameter of type Serializable.
any join point (method execution only in Spring AOP) where the target object has an @Transactional annotation:
@target(org.springframework.transaction.annotation.Transactional)
'@target' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.
any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation:
@within(org.springframework.transaction.annotation.Transactional)
'@within' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.
any join point (method execution only in Spring AOP) where the executing method has an @Transactional annotation:
@annotation(org.springframework.transaction.annotation.Transactional)
'@annotation' can also be used in a binding form :- see the following section on advice for how to make the annotation object available in the advice body.
any join point (method execution only in Spring AOP) which takes a single parameter, and where the runtime type of the argument passed has the@Classified annotation:
@args(com.xyz.security.Classified)
'@args' can also be used in a binding form :- see the following section on advice for how to make the annotation object(s) available in the advice body.
any join point (method execution only in Spring AOP) on a Spring bean named 'tradeService':
bean(tradeService)
any join point (method execution only in Spring AOP) on Spring beans having names that match the wildcard expression '*Service':
bean(*Service)