由于blog各种垃圾评论太多,而且本人审核评论周期较长,所以懒得管理评论了,就把评论功能关闭,有问题可以直接qq骚扰我

SpringAOP与自定义注解实现共性需求

JAVA 西门飞冰 51℃
[隐藏]

1.说明

本文档根据B站UP主分享内容整理,视频原版连接:【IT老齐140】非常实用!Spring AOP与自定义注解实现共性需求

2.介绍

Spring AOP可以帮助我们Java在不修改源代码的前提下实现功能增强,其底层实现基于Java动态代理 或者CGLIB。

以往我们使⽤execution选定具体利⽤AOP扩展哪些类

@Around(value = "execution(* com.fblinux.aop.controller.HelloController.hello(..));")

但是这样使⽤⾮常不方便,因为并不是所有方法都需要被切面增强,往往是今天需要新写了一个方法需要被切面增强,明天又写了一个方法需要被切面增强。针对这种情况,在项目中一般使用自定义注解+AOP实现共性需求

3.应用场景

需要灵活使用共性需求的地方都可以使用该方案

  • 收集上报指定关键方法的入参,执行时间,返回结果等关键信息,用作后期的调优。
  • 关键方法在幂等性的前置校验(基于本地消息表)
  • 类似于 Spring-Retry 模块,提供关键方法多次调用重试机制
  • 提供关键方法自定义的快速熔断,服务降级等职责
  • 关键⽅法的共性⼊参校验
  • 关键方法在执行后的扩展行为,利如记录日志,启动其他任务等。

4.开发过程

(1)新建SpringBoot 工程,引入依赖包

<!--主要是用于创建AOP切面的使用-->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

(2)新建自定义注解,利用@interface关键字自定义注解

//注解用在方法上
@Target(ElementType.METHOD)
//@Retention作用是定义被它所注解的注解保留多久额,RUNTIME运行时,就是这个注解的存活时间
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
  
}

(3)开发切面类,模拟了一个数据上报服务器的过程

//关键代码1:说明当前对象是一个切面
@Aspect
//关键代码2:@Component允许在Spring IOC对当前对象实例化并管理
@Component
public class MethodExporterAspect {

    //关键代码3:说明切面的作用范围,任何增加@AnnotationTest的目标方法都将在执行该切面方法
    //@Around环绕通知,最强大的通知类型,可以控制方法入参,执行,返回结果等各方面细节
    @Around("@annotation(com.fblinux.spring5.aopanno.AnnotationTest)") //这表示AnnotationTest注解修饰的方法使用这个自定义切面进行增强
    public Object methodExporter(ProceedingJoinPoint joinPoint) throws  Throwable{

        long st = System.currentTimeMillis();
        // 执行目标方法,获取方法返回值
        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;
    }
}

(4)切面测试代码,只要是需要上报数据的方法只需要添加我们的自定义注解就可以实现,不需要其他任何多余的步骤。

//⽬标⽅法上增加⾃定义注解
@RestController
public class SampleController {

    @AnnotationTest
    @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;
    }
}

访问接口测试:

http://localhost:8080/list?page=1&rows=100

观察Spring输出结果,Spring输出如下信息说明我们的配置就成功了

image-20221120125335998

转载请注明:西门飞冰的博客 » SpringAOP与自定义注解实现共性需求

喜欢 (0)or分享 (0)