SpringBoot基于AOP实现自定义注解

来源:互联网 发布:全聚合网络电视电脑版 编辑:程序博客网 时间:2024/06/07 08:33

今天写的这个博客是用于,在Spring项目中如何实现自定义注解。
现在我的项目中需要在API工程中记录用户的行为日志。由于行为日志中有行为描述等等的对于每一个接口不同的数据。有两种实现方法:
第一种就是写一个公共方法,然后在每个Controller中手动传参调用,这样冗余代码比较多,而且现在接口都完成了,要每个接口加这样的代码,会很烦。
第二种就是实现在方法上注解。这就需要我们实现自己的自定义注解了。
下面是我的实现方法。

首先我们需要创建一个自定义注解类:

package com.***.utils;import org.springframework.core.Ordered;import org.springframework.core.annotation.Order;import java.lang.annotation.*;/** * 自定义行为日志注解 * Created by yefuliang on 2017/11/2. */@Target({ElementType.METHOD})//@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到@Documented//说明该注解将被包含在javadoc中//最高优先级@Order(Ordered.HIGHEST_PRECEDENCE)public @interface LogAnnotation {    /**     * 行为描述,数据类型为String类型     * @return     */    String behaviorDes() default "";}

这个类非常简单,关于里面的一些注解什么的网上也有很多解释,为了方便大家,我找一些解释放在下面,以便于阅读:
首先最重要的就是@interface这个注解,这个注解就是表明这是一个注解类。我们可以看看其他的一些Spring注解什么的,每个注解类也都有这个注解。这里就不多说了。
然后我们可以看看类上面的几个元注解(至于元注解是什么,网上有很多解释,这里就不多说了):

  • @Target

    这个注解就是表明该注解类能够作用的范围,也就是能够注解在哪,比如 类、方法、参数等。
    下面是他的一些参数:
    @Target(ElementType.TYPE) //接口、类、枚举、注解
    @Target(ElementType.FIELD) //字段、枚举的常量
    @Target(ElementType.METHOD) //方法
    @Target(ElementType.PARAMETER) //方法参数
    @Target(ElementType.CONSTRUCTOR) //构造函数
    @Target(ElementType.LOCAL_VARIABLE)//局部变量
    @Target(ElementType.ANNOTATION_TYPE)//注解
    @Target(ElementType.PACKAGE) ///包
    里面的参数是可以多选的,使用方法比如@Target({ElementType.METHOD,ElementType.TYPE})。

  • @Retention

    这个注解是保留说明,也就是表明这个注解所注解的类能在哪里保留,他有三个属性值:
    RetentionPolicy.SOURCE —— 这种类型的Annotations只在源代码级别保留,编译时就会被忽略
    RetentionPolicy.CLASS —— 这种类型的Annotations编译时被保留,在class文件中存在,但JVM将会忽略
    RetentionPolicy.RUNTIME —— 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
    从上面可以看出一般使用的事第三个属性,其余两个属性,说实话 我也不清楚什么情况下使用这两种。

  • @Documented

    @Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中。

  • @Order

    @Order标记定义了组件的加载顺序,这个标记包含一个value属性。属性接受整形值。如:1,2 等等。值越小拥有越高的优先级。Ordered.HIGHEST_PRECEDENCE这个属性值是最高优先级的属性,它的值是-2147483648,对应的最低属性值是Ordered.LOWEST_PRECEDENCE,它的值是2147483647。

    至于这个类里面的方法,就是注解时需要传入的参数了。
    以下面的的说明一下
    String behaviorDes() default “”;
    很简单 我们可以分成三部分,String \ behaviorDes()\default “”
    我们先看第二个,这个是我们注解时需要传入的参数值的名称,比如上述的用的事behaviorDes,那么我们在注解时就应该这样注解@LogAnnotation(behaviorDes=”测试”),当然如果你只有一个参数需要传的,那么建议各位使用value(),这样注解时会默认传入的,这样我们就可以向其他注解一样@LogAnnotation(“测试”)。
    第一部分的String 是代表这个注解的参数类型。
    第三部分是需要给注解一个默认值,因为如果如果开发人员没有传入值,而且没有默认值的话,会报错。

注解类说完了,那么我们需要一个注解实现类用于实现注解需要实现的功能,那么注解实现类,我是用的事基于AOP的实现类,
首先 我们需要AOP的jar包,maven的pom.xml配置一下代码

        <dependency>            <groupId>org.aspectj</groupId>            <artifactId>aspectjweaver</artifactId>        </dependency>

这里需要注意一下,上面的代码没有版本号,因为我现在的项目有一个同一的版本管理,所以这里不需要加,当然各位看官可以根据自己的需要选择。

注:由于我使用的项目是SpringBoot项目,好像SpringBoot项目是默认开启面向切面编程的,所以这里不需要配置什么,但是如果是Spring MVC项目的话,就需要在配置文件中开启切面编程了,

<aop:aspectj-autoproxy proxy-target-class="true"/>

若不加上上面的配置,会导致方法运行时流程走不到下面的实现类中。

然后我们需要建一个实现类:

package com.***.utils;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.stereotype.Component;/** * 自定义日志注解实现类 * Created by yefuliang on 2017/11/2. */@Aspect@Componentpublic class LogAnnotationAnalytic {    @Before("execution(* com.---.---..*.*(..)) && @annotation(logAnnotation)")    public void logAnnotation(final JoinPoint joinPoint, LogAnnotation logAnnotation ) {        try {            Object[] args = joinPoint.getArgs();            System.out.println("--------------------------注解成功--------------------");        } catch (Exception e) {            e.printStackTrace();        }    }}

首先我们需要给类注解@Aspect,表明该类是一个AOP的类。
@Before(“execution(* com.—.—...(..)) && @annotation(logAnnotation)”)
这一段代码是我从网上找的,
@Before表明在方法前执行。execution(* com.—.—...(..))表明执行切入点扫描的范围,里面的路径由于隐私就用—代替了,抱歉。不过后面的...(..)都是需要原样输入的。@annotation(logAnnotation)需要你输入你实现的是哪个注解类。

当然如果你是使用Aop的@After方式,想要在执行完逻辑代码再拦截,并且你想在方法中获取逻辑代码返回的数据的话。你可以向下面一样:

    @AfterReturning(returning="rvt", pointcut="execution(* com.---.---..*.*(..)) && @annotation(logAnnotation)")    public void logAnnotation(final JoinPoint joinPoint,LogAnnotation logAnnotation,String rvt) {        ....        }

上面的rvt就是逻辑代码返回的数据了。

至于后面两个输入参数就是获取输入的参数Object[] args = joinPoint.getArgs();能获取请求参数的请求体参数。
LogAnnotation logAnnotation能获取注解时传入的数据,使用方法是logAnnotation.behaviorDes()就可以了。

然后我们就可以需要注解的方法或类上面使用注解了

    @LogAnnotation(behaviorDes="测试")    @RequestMapping("/getCommentList")    public String getCommentList(@RequestBody JSONObject request){        String json = request.toJSONString();        return commentService2_2.getCommentList(request.toJSONString());    }

然后请求方法,能够debug出在方法执行之前首先进入到注解实现类里面,并且能过获取到传入的参数和注解时传入的数据。