1.前置知识
动态代理
2.AOP基本概念
AOP面向切面编程,可以不修改源代码进行方法增强,AOP是OOP(面向对象编程)的延续,主要用于日志记录、性能统计、安全控制、事务处理等方面。它是基于代理设计模式,而代理设计模式又分为静态代理和动态代理,静态代理比较简单就是一个接口,分别由一个真实实现和一个代理实现,而动态代理分为基于接口的JDK动态代理和基于类的cglib的动态代理,咱们正常都是面向接口开发,所以AOP使用的是基于接口的JDK动态代理。
- 连接点 Joinpoint :在程序的整个执⾏流程中,可以织⼊切⾯的位置。⽅法的执⾏前后,异常抛出之后等位置
- 切点 Pointcut: 在程序执⾏流程中,真正织⼊切⾯的⽅法。(⼀个切点对应多个连接点)。
- 通知 Advice:通知⼜叫增强,就是具体你要织⼊的代码。 通知包括: 前置通知 后置通知 环绕通知 异常通知 最终通知。
- 切⾯ Aspect: 切点 + 通知就是切⾯。
- 织⼊ Weaving: 把通知应⽤到⽬标对象上的过程。
- 代理对象 Proxy: ⼀个⽬标对象被织⼊通知后产⽣的新对象。 ⽬标对象 Target: 被织⼊通知的对象
3.切入点表达式
execution([访问控制权限修饰符] 返回值类型 [全限定类名]⽅法名(形式参数列表) [异常])
- 访问控制权限修饰符: 可选项。 没写,就是4个权限都包括。 写public就表示只包括公开的⽅法;
- 返回值类型: 必填项。 * 表示返回值类型任意;
- 全限定类名: 可选项。 两个点“..”代表当前包以及⼦包下的所有类。 省略时表示所有的类;
- ⽅法名: 必填项。 *表示所有⽅法。 set*表示所有的set⽅法;
- 形式参数列表: 必填项 。表示没有参数的⽅法 (..) 参数类型和个数随意的⽅法 (*) 只有⼀个参数的⽅法 (*, String) 第⼀个参数类型随意,第⼆个参数是String的;
- 异常: 可选项。 省略时表示任意异常类型
4.基于AspectJ的AOP注解式开发
4.1新建项目
4.2导入依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.22</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.26</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.26</version>
</dependency>
</dependencies>
4.2 目标类
package service;
import org.springframework.stereotype.Service;
@Service
public class orderService {
public void Buy(String car) {
System.out.println("提车---->" + car + "...");
}
}
4.3 切面类
package Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class myAspect {
@Pointcut("execution(* service.orderService*.*(..))")
public void pointCut() {
}
@Before("pointCut()")
public void myBefore() {
System.out.println("前置通知执行了....");
}
@AfterReturning("pointCut()")
public void myAfterReturning() {
System.out.println("后置通知执行了...");
}
@Around("pointCut()")
public Object myAround(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕通知开始...");
Object[] args = point.getArgs();
if (null != args && args.length > 0) {
// 原来参数
Object arg = args[0];
System.out.println("原来的参数:" + arg);
// 更换参数
args[0] = "比亚迪";
}
System.out.println("环绕通知结束...");
return point.proceed(args);
}
@After("pointCut()")
public void myAfter() {
System.out.println("最终通知执行了...");
}
}
4.4 spring配置文件
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描切面包 -->
<context:component-scan base-package="Aspect"></context:component-scan>
<!-- 扫描service包 -->
<context:component-scan base-package="service"></context:component-scan>
<!-- 开启aop的自动代理添加完这句代码后所有带有@Aspect注解的都会生成一个代理对象 -->
<aop:aspectj-autoproxy ></aop:aspectj-autoproxy>
</beans>
4.5 测试
5.通知类型&通知顺序
- 前置通知:@Before ⽬标⽅法执⾏之前的通知
- 后置通知:@AfterReturning ⽬标⽅法执⾏之后的通知
- 环绕通知:@Around ⽬标⽅法之前添加通知,同时⽬标⽅法执⾏之后添加通知。
- 异常通知:@AfterThrowing 发⽣异常之后执⾏的通知
- 最终通知:@After 放在finally语句块中的通知
通知顺序
环绕通知 -> 前置通知 -> 目标方法 -> 后置通知 -> 最终通知
抛出异常通知随时可能执行,根据异常触发决定
6.设置增强类的加载优先级
有多个增强类对同一个方法进行增强,可设置增强类的加载优先级。
举例:比如上面有一个myAspect增强类对orderService类中的方法进行增强,现在有一个myAspect2增强类也对User类中的方法进行增强,那么哪个肯定是哪个增强类先被加载,则先执行哪个增强类。所以我们可以通过在增强类上面添加注解。
@Order(数字类型值)
进行设置类的加载优先级,数字类型值越小优先级越高
@Order(1)//加载优先级
@Component // 通过IOC中的注解将该类实例化到Spring容器
@Aspect // 声明切面类,并为本类生成代理对象
public class myAspect {
.....省略.....
}