Aop:全称为Aspect Oriented Programming(面向切面编程),在实际业务场景中,我们可以通过Aop进行一些业务处理前中后以及异常情况下的一些处理。
一、SpringBoot中使用Aop首先要添加aop的依赖包:
<!-- 面向切面变成AOP相关依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二、定义一个Aop的处理类
- 添加注解@Aspect注解,表示这是一个AOP的切面类,然后添加@Component 表示将这个类交给Spring容器进行管理,然后再定义一个或多个切入点,通常在@Before,@After,@AfterReturning,@AfterThrowing等注解上使用上述定义好的切入点来进行相应的业务处理,比如权限校验,数据统计,日志打印等业务。在定义切入点的时候可以是直接指定一个包,或是这个包中的某个类或是某个方法进行切入,也可以是指定一个注解作为切入点,二者分别使用execution表达式和annotation()进行标注:
@Aspect
@Component
public class AopTestHandler {
private static Logger log = LoggerFactory.getLogger(AopTestHandler.class);
@Pointcut("execution(* com.example.controller..AopController.aopTest2(..))")
public void pointCut(){}
@Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
public void pointCut1(){}
@Pointcut("execution(* com.example.controller..AopController.aopTest3(..))")
public void pointCut2(){}
@Before("pointCut()")
public void doBefore(JoinPoint joinPoint){
log.info("进入到AopTestHandler中的doBefore方法中");
Signature signature = joinPoint.getSignature();
log.info("===={}==={}==={}==={}==={}",signature.getDeclaringType(),
signature.getDeclaringTypeName(),
signature.getModifiers(),
signature.getName(),
signature.getClass());
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
String methodName = httpServletRequest.getMethod();
String url = httpServletRequest.getRequestURL().toString();
String ip = httpServletRequest.getRemoteAddr();
log.info("获取请求中的方法:{},url:{},ip:{}",methodName,url,ip);
}
@After("pointCut()")
public void affter(){
log.info("进入到AopTestHandler中的affter方法中");
}
@AfterReturning("pointCut()")
public void affterReturning(){
log.info("进入到AopTestHandler中的affterReturning方法中");
}
@AfterThrowing(pointcut = "pointCut()",throwing = "ex")
public void affterThrowing(JoinPoint joinPoint,Throwable ex){
log.info("进入到AopTestHandler中的affterThrowing方法中");
}
@Before("pointCut1()")
public void Before(){
log.info("进入到AopTestHandler中的Before方法中测试Annotation类型");
}
@Around("pointCut2()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
log.info("进入到AopTestHandler中的around方法中测试@Around注解");
log.info("AopTestHandler中获取方法名:{}",proceedingJoinPoint.getSignature().getName());
Object obj = proceedingJoinPoint.proceed();
log.info("方法执行结束之后的AopTestHandler中");
return obj;
}
}
注解解释:
1、@Aspect:表示这个类是一个切面类
2、@Pointcut(...):表示这是一个切入点,里面有两种定义方式:execution(* com.example.controller..AopController.aopTest1(..))指定某个包下面的某些类中的某些方法进行切入,第一个“*”表示返回类型,“com.example.controller”表示包名,“..”表示这个包下的所有包及子包,“AopController”表示这个类,也可以将它换成“*”表示所有类,“*(..)”表示这个类下的所有方法,“..”表示任何参数的方法。annotation()用于标示某个注解做为切入点,可以是自定义注解,上述案例中以GetMapping注解做为切入点。
3、@Before():表示在这个切入点之前执行的一些处理。
4、@After():表示在切入点执行之后进行的一些处理。
5、@AfterReturning():表示在切入点进行返回数据的时候进行的一些处理。
6、@AfterThrowing():标示在切入点抛出异常之后进行的一些处理。
7、@Around():环绕增强型,在执行目标方法前和目标方法之后都会进行执行。
参数解释:
1、JoinPoint:可以通过JoinPoint对象获取一个Signature,通过Signature获取调用的类名,方法名,等信息。
三、自定义一个Controller类进行aop测试:
- aopTest1用来测试execution()表达式,appTest2用来测试annotation()表达式
@RestController
@Api(value="AopTest")
public class AopController {
private static Logger log = LoggerFactory.getLogger(AopController.class);
@RequestMapping("/aopTest1/{param}"",method = RequestMethod.GET)
@ApiOperation(value="execution测试")
public JsonResult aopTest1(@PathVariable @ApiParam(value = "param") String param){
log.info("进入到AopController中的aopTest1方法中");
log.info("获取到的参数为:{}",param);
// try{
// int i = 1/0;
// }catch (Exception e){
// throw new BusinessException(BusinessExceptionEnum.BUSINESS_EXCEPTION);
// }
return new JsonResult();
}
@PostMapping(value ="aopTest2")
@ApiOperation(value="annotation测试")
public JsonResult aopTest2(@RequestParam @ApiParam(value = "param1") String param1, @RequestParam @ApiParam(value="param2") String param2){
log.info("获取到参数:{}--{}",param1,param2);
return new JsonResult("0","annotation测试");
}
@RequestMapping(value = "/aopTest3",method = RequestMethod.GET)
@ApiOperation("测试@Around注解")
public JsonResult aopTest3(){
log.info("进入到AopController中的aopTest3方法中");
return new JsonResult();
}
}
四、测试AOP
启动springboot工程,用swagger进行测试上述定义好的方法,并且在控制台可以看出上述方法的执行顺序:
1、测试execution()表达式
控制台打印信息:从打印信息可以看出AOP中各个注解对应的方法的执行顺序:Before -> controller方法 -> AfterReturning -> After
2、annotation表达式测试:
控制台打印信息:因为只是annotation表达式,各个注解的执行顺序在上述execution表达式测试中已经体现,现在不再赘述。
3、@Around注解测试
控制台信息打印: