讀萬卷書,行萬里路。
定義切面
在使用AspectJ注解定義切面時,需要引入aspectjrt.jar 和 aspectjweaver.jar。
1.使用@Aspect注解標注類為切面。
2.使用以下AspectJ注解來聲明切面通知方法:
1)@After:通知方法在目標方法返回或拋出異常后調用;
2)@AfterReturning:通知方法在目標方法返回后調用;
3)@AfterThrowing:通知方法在目標方法拋出異常后調用;
4)@Around:通知方法將目標方法封裝起來;
5)@Before:通知方法在目標方法調用之前執行。
如下,使用AspectJ注解將普通的POJO類標注為切面:
package chapter4.practice1; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; /** * POJO * 使用@Aspect標注該POJO也是切面 */ @Aspect public class Audience { /** * 在chapter4.practice1.Performance類的perform方法調用前執行 */ @Before("execution(** chapter4.practice1.Performance.perform(..))") public void drink() { System.out.println("Drink water..."); } /** * 在chapter4.practice1.Performance類的perform方法返回后執行 */ @AfterReturning("execution(** chapter4.practice1.Performance.perform(..))") public void eat() { System.out.println("Eat food..."); } /** * 在chapter4.practice1.Performance類的perform方法拋出異常后執行 */ @AfterThrowing("execution(** chapter4.practice1.Performance.perform(..))") public void refund() { System.out.println("Demand refund..."); } }
在上述代碼中可發現相同的切點表達式重復定義了三次,我們可以使用@Pointcut注解在@AspectJ切面定義可重復使用的切點。
package chapter4.practice1; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; /** * POJO * 使用@Aspect標注該POJO也是切面 */ @Aspect public class Audience { /** * 使用@Pointcut設置切點表達式 */ @Pointcut("execution(** chapter4.practice1.Performance.perform(..))") public void performance() {} /** * 在chapter4.practice1.Performance類的perform方法調用前執行 */ @Before("performance()") public void drink() { System.out.println("Drink water..."); } /** * 在chapter4.practice1.Performance類的perform方法返回后執行 */ @AfterReturning("performance()") public void eat() { System.out.println("Eat food..."); } /** * 在chapter4.practice1.Performance類的perform方法拋出異常后執行 */ @AfterThrowing("performance()") public void refund() { System.out.println("Demand refund..."); } }
啟用自動代理
以上代碼創建了一個簡單切面,我們還需啟用自動代理,這樣@Aspect標注的類才會被視為切面,這些注解才會被解析。啟用自動代理的方式以下兩種:
1.在Java配置類JavaConfig使用@EnableAspectJAutoProxy注解啟用自動代理功能。
package chapter4.practice1; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy @ComponentScan public class JavaConfig { @Bean public Audience audience() { return new Audience(); } }
2.在XML配置中使用Spring AOP命名空間中的<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:aop="http://www.springframework.org/schema/aop" xmlns:c="http://www.springframework.org/schema/c" xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd"> <context:component-scan base-package="chapter4.practice1" /> <aop:aspectj-autoproxy/> <bean id="audience" class="chapter4.practice1.Audience"></bean> </beans>
Spring的AspectJ自動代理僅使用@AspectJ作為創建切面的指導,切面依然是基於代理的。如果想利用AspectJ的所有功能,必須在運行時使用AspectJ並且不依賴Spring來創建基於代理的切面。