什么是AspectJ
AspectJ不是SPring的组成部分,是一个独立AOP框架,一般把AspectJ和Spring框架一起使用,进而进行AOP操作。
基于AspectJ实现AOP操作
- 基于XML配置文件实现
- 基于注解方式实现(方便,常用)
切入点表达式
-
切入点表达式作用:知道对哪个类里面的哪个方法进行增强。
-
语法结构:
execution([权限修饰符] [返回类型] [类全路径] [方法名称] [参数列表])
举例1:对dao.BookDao类中的add方法进行增强
execution(* dao.BookDao.add(…))
举例2:对dao.BookDao类中的所有方法进行增强
execution(* dao.BookDao.*(…))
举例3:对dao包中的所有类,以及类中的所有方法进行增强
execution(* dao.*.*(…))
基于注解方式实现
-
创建一个类,在类里定义方法
public class User { public void add(){ System.out.println("add......."); } }
-
创建增强类(编写增强逻辑)
在增强类里面,创建方法,让不同的方法代表不同通知类型
//增强的类 public class UserProxy { //前置通知 public void before(){ System.out.println("before......"); } }
-
进行通知的配置
(1)在spring配置文件或配置类中开启注解扫描(这里直接用一个配置类来实现)
package config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration //作为配置类,代替xml配置文件 @ComponentScan(basePackages = {"spring5"}) //该条配置等价与 <context:component-scan base-package="spring5"></context:component-scan> public class SpringConfig { }
(2)使用注解创建User和UserProxy类对象
只要在这两个类上面加上@Component注解就行了
(3)在增强类上面添加@Aspect注解
(4)在spring配置文件中开启生成代理对象
在配置类中添加@EnableAspectJAutoProxy注解即可
-
配置不同类型的通知
共有以下5中不同的通知类型
- @Before():前置通知,在增强的方法执行之前执行
- @AfterReturning():后置通知(返回通知),在增强的方法执行之后执行,增强的方法出现异常不执行
- @After(),最终通知:在增强的方法执行之后执行,且无论增强的方法有没有出现异常都会执行
- @AfterThrowing:异常通知,在增强的方法出现异常的时候才会执行
- @Around:环绕通知,在增强方法执行的前后都会执行
(1)在增强类中作为通知的方法上面添加通知类型注解,使用切入点表达式配置。
即在UserProxy类中的before方法的上面加上@Before(value = “execution(* spring5.aop.User.add(…))”),以下是最终的UserProxy类。
//增强的类 @Component @Aspect //生成代理对象 public class UserProxy { //前置通知 @Before(value = "execution(* spring5.aop.User.add(..))") public void before(){ System.out.println("before......"); } }
-
对公共切入点进行抽取(根据切入点表达式)
创建一个公共切入点抽取的方法(随意命名),加上@Pointcut(value = “execution(* spring5.aop.User.add(…))”)注解,value为需要抽取的切入点表达式。
//相同切入点抽取 @Pointcut(value = "execution(* spring5.aop.User.add(..))") public void point1(){ }
将之前的五种通知的注解中调用,如下
//增强的类 @Component @Aspect //生成代理对象 public class UserProxy { //相同切入点抽取 @Pointcut(value = "execution(* spring5.aop.User.add(..))") public void point1(){ } //前置通知 @Before(value = "point1()") public void before(){ System.out.println("before......"); } @AfterReturning(value = "point1()") public void afterReturning(){ System.out.println("afterReturning......"); } @After(value = "point1()") public void after(){ System.out.println("after......"); } //异常通知 @AfterThrowing(value = "point1()") public void afterThrowing(){ System.out.println("afterThrowing......"); } //环绕通知 @Around(value = "point1()") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前....."); proceedingJoinPoint.proceed(); System.out.println("环绕之后....."); } }
-
多个增强类,可用@order(int*)设置增强类的优先级,数字越小,优先级越高。
@Component @Aspect //生成代理对象 public class PersonProxy { @Before(value = "execution(* spring5.aop.User.add(..))") @Order(1) public void before(){ System.out.println("Person before......"); } }
基于配置文件方式就说了,因为这种方法在开发中根本不会用到,因为注解方式更为方便。