利用AOP实现自定义注解-springboot

513 阅读2分钟

前置知识

  • 需要用到的几个元注解
  • springboot 中如何使用aop

步骤

1、依赖

因为需要使用到springboot框架和aop技术,并且最后的测试用的是单元测试,因此需要引入以下依赖

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
</dependency>

2、定义注解

定义注解需要用到Java中的元注解,具体使用需要看自己的业务而定,并且注解中可以加入字段。

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LearnAnnotation {
    public String desc() default "";
}

3、编写aop实现类

利用aop使自定义的注解生效

@Aspect
@Component
public class LearnAop {

    @Pointcut("@annotation(org.example.myAnnotation.LearnAnnotation)")
    private void cut(){}

    @Around("cut()")
    public void advice(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取连接点方法运行时的入参
        Object[] args = joinPoint.getArgs();
        // 获取目标方法所在的对象信息
        Class<?> targetClass = joinPoint.getTarget().getClass();
        // 获取连接点方法对象
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取目标方法名称
        String methodName = signature.getName();
        // 获取目标方法信息
        Method targetMethod = targetClass.getDeclaredMethod(methodName,signature.getParameterTypes());
        // 获取自定义注解信息
        LearnAnnotation annotation = targetMethod.getAnnotation(LearnAnnotation.class);

        joinPoint.proceed();
    }
}

4、使用自定义注解并验证是否成功

使用

@Component
public class LearnServer {

    @LearnAnnotation
    public void test1(String args){
        System.out.println(args);
    }
}

验证

@SpringBootTest
@RunWith(SpringRunner.class)
public class MainTest {

    @Autowired
    private LearnServer learnServer;

    @Test
    public void test1(){
        learnServer.test1("123");
    }
}

解释

1、常用的元注解

  • @Retention:指定其所修饰的注解的保留策略
  • @Document:该注解是一个标记注解,用于指示一个注解将被文档化
  • @Target:用来限制注解的使用范围
  • @Inherited:该注解使父类的注解能被其子类继承

@Retention 用于表明注解保留在Java运行的哪个阶段,其中有三个可选择的值

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     * 编译阶段
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     * 由编译器记录在类文件中,但是不保存在运行阶段,默认字段
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     * 编译和运行阶段都保留
     */
    RUNTIME
}

@Document:可以被javadoc识别并提取成文档 @Target:注解可以在哪些地方使用,可以选择多个

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

@Inherited:假如父类使用了@Inherited修饰的注解,那么子类也自动使用父类的注解

2、aop类的编写

定义切点,并且切点指向自定义的注解,使用的是@annotation注解,其他的业务逻辑就是aop的使用方法。其中可以通过ProceedingJoinPoint对象获取注解的属性并进行操作。