目录
Spring AOP
1、AOP组成
1.1、切面(Aspect)
1.2、切点(Pointcut)
1.3、通知(Advice)
1.4、连接点(join point)
2、Spring AOP实现
2.1、添加Spring AOP依赖
2.2、定义切面(创建切面类)
2.3、定义切点(配置拦截规则)
2.4、定义通知的时限
3、Spring AOP实现原理
动态代理
面向切面编程,是对某一类事情的集中处理
切面在程序中就是一个处理某方面具体问题的一个类。类里面包含了很多方法,这些方法就是切点和通知
用来进行主动拦截的规则(配置)
程序中被拦截请求触发的具体动作就是在通知中实现的具体业务代码。其实就是AOP具体的执行动作
a.前置通知:在执行目标方法之前执行的方法就叫做前置通知
b.后置通知:在执行了目标方法之后执行的方法就叫做后置通知
c.异常通知:在执行目标方法出现异常时,执行的通知
d.返回通知:在目标方法执行了返回数据(return)时,执行的通知
e.环绕通知:在目标方法执行的周期范围内(执行之前、执行中、执行后)都可以执行的方法叫做环绕通知
可能会触发AOP规则的所有点(所有请求)
创建Spring Boot项目时没有Spring AOP框架,需添加Spring AOP依赖
org.springframework.boot
spring-boot-starter-aop
2.7.9
@Aspect //告诉框架我是一个切面类
@Component //随着框架的启动而启动
public class UserAspect {
}
@Aspect //告诉框架我是一个切面类
@Component //随着框架的启动而启动
public class UserAspect {
/*
切点(配置拦截规则)
*/
@Pointcut("execution(* com.example.demo.controll.UserController.*())")
public void pointcut(){
}
}
/*
前置通知
*/
@Before("pointcut()")
public void beforeAdvice(){
System.out.println("执行了前置通知");
}
/*
后置通知
*/
@After("pointcut()")
public void AfterAdvice(){
System.out.println("执行了后置通知");
}
代码实现:
@Aspect //告诉框架我是一个切面类
@Component //随着框架的启动而启动
public class UserAspect {
/*
切点(配置拦截规则)
*/
@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
public void pointcut(){
}
/*
前置通知
*/
@Before("pointcut()")
public void beforeAdvice(){
System.out.println("执行了前置通知");
}
/*
后置通知
*/
@After("pointcut()")
public void AfterAdvice(){
System.out.println("执行了后置通知");
}
/*
环绕通知
*/
@Around("pointcut()")
public Object roundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("进入环绕通知");
Object obj=null;
//执行目标方法
obj=joinPoint.proceed();
System.out.println("退出环绕通知");
return obj;
}
}
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/hi")
public String sayHi(String name){
System.out.println("执行了 sayHi 方法");
return "hi,"+name;
}
@RequestMapping("/hello")
public String sayHello(){
System.out.println("执行了 sayHello 方法");
return "hello,baekhyun";
}
}
@RestController
@RequestMapping("/art")
public class ArticleController {
@RequestMapping("/hi")
public String sayHi(){
return "hi,world";
}
}
切点表达式:
execution(<修饰符><返回类型><包.类.方法(参数)><异常>)
修饰符(一般省略)
public 公共方法
* 任意
返回值(不能省略)
void 返回没有值
String 返回值字符串
* 任意
方法名(不能省略)
addUser 固定方法
add* 以add开头
*Do 以Do结尾
* 任意
(参数)
() 无参
(int) 一个整型
(int,int) 两个
(..) 参数任意
JDK和CGLIB实现的区别:
1. JDK实现,要求被代理类必须实现接口,之后是通过InvocationHandler及Proxy,在运行时动态的在内存中生成了代理类对象,该代理对象是通过实现同样的接口实现(类似静态代理接口实现的方
式),只是该代理类是在运行期时,动态的织入统一的业务逻辑字节码来完成。
2. CGLIB实现,被代理类可以不实现接口,是通过继承被代理类,在运行时动态的生成代理类对象。