3、进行AOP操作
(1)创建类,该类为被增强类,在类里面定义方法
package com.aopanno; public class User { public void add() { System.out.println("add......"); } }
(2)创建增强类(编写增强逻辑),在增强类里面,创建方法,让不同的方法代表不同通知类型
//增强的类 public class UserProxy { public void before() { System.out.println("before......"); } public void after(){ System.out.println("after........"); } public void afterReturning(){ System.out.println("afterReturning........"); } public void afterThrowing(){ System.out.println("afterThrowing"); } public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前......"); //被增强的方法执行 proceedingJoinPoint.proceed(); System.out.println("环绕之后......"); } }
(3)进行通知的配置
在spring文件中先开启注解扫描:
<context:component-scan base-package="com.aopanno"/>
使用注解创建User和UserProxy对象,并在增强的类上面添加注解@Aspect
@Component @Aspect //生成代理对象
在spring配置文件中开启生成代理对象
<aop:aspectj-autoproxy/>
配置不同类型的通知,在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式进行配置。
@Component @Aspect //生成代理对象 public class UserProxy { //前置通知,里面用切入点表达式 @Before(value = "execution(* com.aopanno.User.add(..))") public void before() { System.out.println("before......"); } //在方法之后执行,无论异常与否都执行 @After(value = "execution(* com.aopanno.User.add(..))") public void after(){ System.out.println("after........"); } //在返回值之后执行,只有在方法正常返回的情况下才执行 @AfterReturning(value = "execution(* com.aopanno.User.add(..))") public void afterReturning(){ System.out.println("afterReturning........"); } @AfterThrowing(value = "execution(* com.aopanno.User.add(..))") public void afterThrowing(){ System.out.println("afterThrowing"); } @Around(value = "execution(* com.aopanno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前......"); //被增强的方法执行 proceedingJoinPoint.proceed(); System.out.println("环绕之后......"); } }
(4) 对相同的切入点进行抽取
大家会发现切入点的表达式都是一样的,那如何对相同的切入点进行抽取呢?类似于静态方法,该方法可以被共享,所以我们定义一个方法,将切入点表达式放入该方法中,只需调用该方法即可。此种做法方便代码的后期维护,比如切入点表达式发生变化,无需一个个费劲地去改,只需改方法里的代码。
@Component @Aspect //生成代理对象 public class UserProxy { //相同切入点抽取 @Pointcut(value ="execution(* com.aopanno.User.add(..))") public void pointDemo(){ } //前置通知,里面用切入点表达式 @Before(value = "pointDemo()") public void before() { System.out.println("before......"); } //在方法之后执行,无论异常与否都执行 @After(value = "pointDemo()") public void after(){ System.out.println("after........"); } //在返回值之后执行,只有在方法正常返回的情况下才执行 @AfterReturning(value = "pointDemo()") public void afterReturning(){ System.out.println("afterReturning........"); } @AfterThrowing(value = "pointDemo()") public void afterThrowing(){ System.out.println("afterThrowing"); } @Around(value = "pointDemo()") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前......"); //被增强的方法执行 proceedingJoinPoint.proceed(); System.out.println("环绕之后......"); } }
(5)结果分析
从结果可以看出每个通知的执行 。前置通知before,作用在被增强方法add方法的前面,环绕通知around,围绕add方法,并且在前置通知和最终通知之前,最终通知after作用在后置通知afterReturning之前,此外我们还发现,异常通知还未出现。假设程序出现异常,每个通知的执行顺序又会有怎样的变化呢?
当出现异常时,异常通知afterThrowing出现,且最终通知after出现,这也是它为什么叫最终通知了。
(6)当有多个增强类对同一个方法进行增强,可以设置增强类的优先级
在增强类上面添加注解@Order(数字值),数字越小,优先级就越高,再创建一个增强方法:
package com.aopanno; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Component @Aspect @Order(1) public class PersonProxy { @Before(value = "execution(* com.aopanno.User.add(..))") public void before() { System.out.println("Person Before......"); } }
@Order(2) @Component @Aspect //生成代理对象 public class UserProxy { //相同切入点抽取 @Pointcut(value ="execution(* com.aopanno.User.add(..))") public void pointDemo(){ }
结果如下:
(7)完全注解开发
创建配置类,不需要创建xml配置文件,@Configuration,添加此注解,系统就知道这是配置类,@ComponentScan,表示开启注解扫描,@EnableAspectJAutoProxy,开启Aspect生成代理对象
package com.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @ComponentScan(basePackages = {"com"}) @EnableAspectJAutoProxy(proxyTargetClass = true) public class ConfigAop { }
@Test public void test(){ ApplicationContext context=new AnnotationConfigApplicationContext(ConfigAop.class); User user = context.getBean("user", User.class); user.add(); }
需要注意的是,Junit测试单元写法有点不同,后面表示加载注解配置文件