读万卷书,行万里路。
定义切面
在使用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来创建基于代理的切面。