概述
使用 AOP(面向切面编程)可以帮助你实现横切关注点(如日志记录、事务管理、权限控制等)的分离,比如你对外提供了一个接口,接口上线后产品又要求需要对接口的出入参做记录,以提供数据支撑供业务分析以及方便问题排查。
你想着,这不简单嘛,我只要在接口返回的时候发送一个MQ 记录下来不就行了嘛,于是你兴致勃勃的打开代码一看,傻眼了,这个接口里有众多的if()
判断,并且每个if
判断里都会有结果返回,难道在所有的if
返回前都发送一个消息嘛?示例代码如下:
class BussinessService{
public Response invoke(Param param){
if(参数校验失败){
// 发送消息?
return new Response(400,参数校验失败);
}
if(无数据返回){
// 发送消息?
return new Response(204,返回内容为空);
}
// 。。。。。省略一大堆 if 判断及返回
// 正常业务逻辑
// 发送消息?
return new Response(200,success,result);
}
}
在所有的if
返回前都执行一个逻辑有两个点非常不友好,一个点是如果将来新增if
判断,仍然需要新增发送消息代码,第二个点是太具有侵入性,需要修改原来代码。这时候,使用切面就是一个比较好的选择。在日常开发中,Spring Aop
就是较为常见的切面的选择。下面就对 Spring Aop
切面做详细介绍。
Spring Aop
的基本使用
1.添加依赖(可选)
我们现在常用的是 SpringBoot 项目,一般来说,依赖会被自动引入。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.创建切面类
这里我们假设场景是在某个方法执行前,进行日志的打印,这里创建一个名为LoggingAspect
的切面类。
切面类是用来定义横切逻辑的地方,我们需要使用@Aspect
注解标明这是一个切面类,此外,需要使用@Component
使 SpringBoot 项目能够扫描到这个 Bean。
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
}
3.切面类配置
3.1 定义切入点表达式
简单来说,切入点表达式就是说你要拦截哪个方法的调用。
这里我们假设要拦截ControllerTest#test
方法的执行,方法定义如下,则我们的切入点表达式定义为:"execution(* com.gumei.webapp.ControllerTest.test(..))"
,这里我们先不细究切面表达式的定义规则,先将功能实现,在下文中会对切面表达式的规则做详细介绍。
@Controller
@CrossOrigin
public class ControllerTest {
@ResponseBody
@RequestMapping("/test")
public Response test(Param param){
Response response = new Response();
response.setAge(param.age);
response.setName(param.name);
response.setDate(new Date());
response.setLocalDateTime(LocalDateTime.now());
return response;
}
}
3.2 使用通知Advice
通俗的理解通知就是在方法的某个时间节点执行时发出的消息,比如要在方法调用之前监听则使用@Before
通知。至于不同通知的类型及可接收/返回的参数,也将在下文中进行详细介绍。
import org.aspectj.lang.