Spring Boot中的切面AOP
1. 什么是AOP?
AOP是OOP的延续,是Aspect Oriented Programming的缩bai写,意思du是面向切面编程。可以通过预zhi编译方式dao和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。
2. 在Spring Boot中然后使用AOP
2.1先导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency
2.2 实现AOP切面
创建一个切面类 ,在该类上需要加入@Aspect和@Component注解:
package liz.com.springtest.handler;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @author linjiazeng
* @version 1.0
* @date 2020/12/21 14:00
**/
@Aspect
@Component
public class TestAspectHandler {
/*
1.@Pointcut:定义一个切面,即上面所描述的关注的某件事入口。
2.@Before:在做某件事之前做的事。
3.@After:在做某件事之后做的事。
4.@AfterReturning:在做某件事之后,对其返回值做增强处理。
5.@AfterThrowing:在做某件事抛出异常时,处理。
* */
// G:\代码\Springboot_Study\springtest\src\main\java\liz\com\springtest\controller
@Pointcut("execution(* liz.com.springtest.controller..*.*(..))")
public void pointCut1(){}
//具体到某个方法的切面
@Pointcut("execution(* liz.com.springtest.controller.AspectController.getAfter())")
public void pointCut2(){}
@Pointcut("execution(* liz.com.springtest.controller.AspectController.getAfterReturning())")
public void pointCut3(){}
@Pointcut("execution(* liz.com.springtest.controller..*.*(..))")
public void pointCut4(){}
/*
* @Pointcut 注解指定一个切面,定义需要拦截的东西,这里介绍两个常用的表达式:
* 一个是使用execution() ,另一个是使用 annotation() 。
* 以 execution(* com.itcodai.course09.controller..*.*(..))) 表达式为例,
* 语法如下:
* execution() 为表达式主体
第一个 * 号的位置:表示返回值类型, * 表示所有类型
包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,
liz.com.contcroller 包、子包下所有类的方法
第二个 * 号的位置:表示类名, * 表示所有类
*(..) :这个星号表示方法名, * 表示所有的方法,后面括弧里面表示方法的参数,两个句点
表示任何参数
annotation() 方式是针对某个注解来定义切面,比如我们对具有 @GetMapping 注解的方法做切面,
可以如下定义切面
@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
public void annotationCut() {}
*
* */
/*
@Before 注解指定的方法在切面切入目标方法之前执行,可以做一些 log 处理,也可以做一些信息的
统计,比如获取用户的请求 url 以及用户的 ip 地址等等,这个在做个人站点的时候都能用得到,都是常
用的方法。例如:
*/
@Before("pointCut1()")
public void doBefore(JoinPoint joinPoint){
System.out.println("=======进入到doBefore方法========");
//获取签名
Signature signature = joinPoint.getSignature();
//获取切入的包名
String declaringTypeName = signature.getDeclaringTypeName();
//获取即将执行的方法
String funcName = signature.getName();
System.out.println("即将执行的方法名为:"+funcName+"属于"+declaringTypeName);
//在这里可以加入很多执行的方法
}
/*@After 注解和 @Before 注解相对应,指定的方法在切面切入目标方法之后执行,也可以做一些完成
某方法之后的 log 处理。
c*/
@After("pointCut2()")
public void after(){
System.out.println("==============进入After的执行方法===============");
//这里可以加入很多的业务逻辑
}
/*需要注意的是:在 @AfterReturning 注解 中,属性 returning 的值必须要和参数保持一致,否则会
检测不到。该方法中的第二个入参就是被切方法的返回值,在 doAfterReturning 方法中可以对返回
值进行增强,可以根据业务需要做相应的封装。*/
@AfterReturning(pointcut = "pointCut3()", returning = "result")
public void AfterReturning (JoinPoint joinPoint,Object result){
System.out.println("==============执行AfterReturning方法===============");
System.out.println("加强的结果:"+result);
//这里可以加入很多的业务逻辑
}
/*
@AfterReturning 注解和 @After 有些类似,区别在于 @AfterReturning 注解可以用来捕获切入方
法执行完之后的返回值,对返回值进行业务逻辑上的增强处理,例如:
*/
@AfterThrowing(pointcut = "pointCut4()",throwing = "ex")
public void AfterThrowing(JoinPoint joinPoint,Exception ex){
System.out.println("==============执行AfterThrowing方法===============");
System.out.println(ex.getCause().toString());
}
}
/*
需要注意的是:在 @AfterReturning 注解 中,属性 returning 的值必须要和参数保持一致,否则会
检测不到。该方法中的第二个入参就是被切方法的返回值,在 doAfterReturning 方法中可以对返回
值进行增强,可以根据业务需要做相应的封装。
*/
测试代码:
package liz.com.springtest.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author linjiazeng
* @version 1.0
* @date 2020/12/21 14:25
**/
@RestController
@RequestMapping("aspect")
public class AspectController {
@GetMapping("getBefore")
public void getBefore(){
System.out.println("getBefore方法执行");
}
@GetMapping("getAfter")
public void getAfter(){
System.out.println("getAfter方法执行");
}
@GetMapping("getAfterReturning")
public String getAfterReturning(){
return "hello getAfterReturning ";
}
@GetMapping("getAfterThrowing")
public void getAfterThrowing(){
int i = 1/0;
}
}