Spring AOP可以帮助我们Java在不修改源代码的前提下实现功能增强,其底层实现基于JDK动态代理或者CGlib。
以往使用execution选定具体利用AOP扩展那些类,非常不灵活。
现在我们可以使用自定义注解实现AOP满足共性需求。
项目结构
一、新建SpringBoot 2.x项目,在pom文件中引入依赖
<!--Spring切面类底层的依赖-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
<!--用来打印日志-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<!--JSON序列化-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
二、构建自定义注解
自定义注解是一个标识符,用来指定哪一个方法可以进行扩展,所以注解类里不需要有任何实现。
代码如下:
//注解的作用目标,表示该注解用在方法上
@Target(ElementType.METHOD)
//注解的保留时间,表示注解在运行时保留
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodExporter {
}
@interface:用来说明是个注解类
三、开发切面类
代码如下:
//说明当前对象是个切面
@Aspect
//将当前对象交给Spring IOC实例化并管理
@Component
//用于打印日志
@Slf4j
public class MethodExporterAspect {
//@Around环绕通知,最强大的通知类型,可以控制方法入参、执行、返回结果等各方面细节
//里面的表达式@annotation用来说明某个方法上书写了MethodExporter注解的话就会执行下面的方法
//对目标方法进行增强
@Around("@annotation(com.doll.aopanno.annoation.MethodExporter)")
public Object methodExporter(ProceedingJoinPoint joinPoint) throws Throwable{
long st = System.currentTimeMillis();
//joinPoint:连接点;执行目标方法,获取返回值; proceed:继续进行
Object proceed = joinPoint.proceed();
long et = System.currentTimeMillis();
ObjectMapper mapper = new ObjectMapper();
//将入参JSON序列化
String jsonParam = mapper.writeValueAsString(joinPoint.getArgs());
//将返回结果JSON序列化
String jsonResult = null;
if (proceed!=null){
jsonResult = mapper.writeValueAsString(proceed);
}else {
jsonResult = "null";
}
//模拟上报过程
log.info("正在上报服务器调用过程:\ntarget:{}.{}()\nexecution:{}ms,\nparameter:{}\nresult:{} "
,joinPoint.getTarget().getClass().getSimpleName()
,joinPoint.getSignature().getName()
,(et-st)
,jsonParam
,jsonResult);
return proceed;
}
}
四、测试自定义注解
在目标方法上增加自定义注解
代码如下:
@RestController
public class SampleController {
@MethodExporter
@GetMapping("/list")
public Map list(int page, int rows) {
Map result = new LinkedHashMap();
result.put("code", 0);
result.put("message", "success");
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}
}
如果你是idea2020以后的版本应该可以看见@GetMapping注解括号里有一个地球图标,点击,然后选择在HTTP客户端中打开。
###写入参数,然后点击左侧运行绿色箭头,运行/调试 HTTP请求
GET http://localhost:8080/list?page=1&rows=100
可以看到输出结果,成功使用AOP+自定义注解的方式增强方法。