自定义注解

在SpringBoot相关开发中,我们常常用到各种注解。如@Aotuwired,@Data等等,极大的提高了开发效率,降低代码耦合度。

往往官方只提供常用注解,而自己稀奇古怪的想法就需要自定义开发。

注解分类

@Target(ElementType.?)

通过Java盒子类型以及常用注解可以推断出几种注解 :

  • 类注解 如:@Data
  • 方法注解、 如:@GetMapping
  • 属性注解、 如:@Value
  • 形参注解、 如:@RequestBody
java 复制代码
@类注解
public class 注解分类{
    
    @属性注解
    public String 属性;


    @方法注解
    public void 方法(){
    }

    
    public void 方法(@参数注解 String 参数)
}

参考Demo

java 复制代码
@Target(ElementType.METHOD)
public @interface InterDemo {
    String value() default "";
}

源码

而根据源码中的枚举类型可以看到,Java代码类型均有对应的类型匹配。

java 复制代码
//---------------------------------------源码---------------------------------
public enum ElementType {
    /** Class, interface (including annotation interface), enum, or record
     * declaration */
    TYPE,

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

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation interface declaration (Formerly known as an annotation type.) */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

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

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

    /**
     * Module declaration.
     *
     * @since 9
     */
    MODULE,

    /**
     * Record component
     *
     * @jls 8.10.3 Record Members
     * @jls 9.7.4 Where Annotations May Appear
     *
     * @since 16
     */
    RECORD_COMPONENT;
}

注解存在多久

为什么这么问?

每次项目启动都会出现一个文件夹 out/target ,里面的代码为class文件,在计算机中只有0|1。那么注解将被解析成什么,注解存在到什么时候?

生命周期有三个阶段:1、Java源文件阶段;2、编译到class文件阶段;3、运行期阶段。

java 复制代码
public enum RetentionPolicy {

    //注解将被编译器忽略掉
    SOURCE,


    //注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留
    CLASS,


    //注解将被编译器记录在class文件中,并且运行时会被虚拟机保留,能通过反射被读取
    RUNTIME
}

一般常用 : RUNTIME。

注解怎么用,如何生效

我要给注解添加功能,功能在哪添加呢。注解放到类上,是不是包裹一个类呢?放到方法上呢?既然包裹住,那就有执行前和执行后,为什么不用切面当作注解的功能区

基本配置

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
java 复制代码
@Aspect
@Component
public class AspectDemo {
}

定义切入点

@Pointcut("@annotation(文件路径)") 路径参考 :life.xuxie.www.inter.InterDemo

java 复制代码
@Aspect
@Component
public class AspectDemo {
    //定义切入点
    @Pointcut("@annotation(life.xuxie.www.inter.InterDemo)")
    public void interDemoPointcut() {}
}

使用如 @Before 和 @After 注解来定义切面前置和后置通知

java 复制代码
@Slf4j
@Aspect
@Component
public class AspectDemo {

    @Pointcut("@annotation(life.putl.wx.inter.InterDemo)")
    public void interDemoPointcut() {}

    @Before("interDemoPointcut()")
    public void before() {
            System.out.println("Before");
    }

    @After("interDemoPointcut()")
    public void after() {
            System.out.println("After");
    }
}

注解参数获取

通过上面的代码可以发现注解生效一部分了,因为我们定义的值根本没用到....

获取参数方法就是上面说的通过反射,我们需要在方法中添加形参

获取方法签名:通过 joinPoint.getSignature() 获取方法签名,并将其转换为 MethodSignature。

获取方法对象:通过 MethodSignature 获取方法对象 Method。

获取注解:通过 method.getAnnotation(InterDemo.class) 获取方法上的 @InterDemo 注解。

提取注解值:从注解对象中提取 value 值,并打印出来。

java 复制代码
@Slf4j
@Aspect
@Component
public class AspectDemo {

    @Pointcut("@annotation(life.putl.wx.inter.InterDemo)")
    public void interDemoPointcut() {}

    @Before("interDemoPointcut()")
    public void before(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        InterDemo interDemo = method.getAnnotation(InterDemo.class);
        if (interDemo != null) {
            String value = interDemo.value();
            System.out.println("Before: " + value);
        }
    }

    @After("interDemoPointcut()")
    public void after(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        InterDemo interDemo = method.getAnnotation(InterDemo.class);
        if (interDemo != null) {
            String value = interDemo.value();
            System.out.println("After: " + value);
        }
    }

    @Around("interDemoPointcut()")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        // 执行目标方法
        Object result = joinPoint.proceed();

        long endTime = System.currentTimeMillis();
        long executionTime = endTime - startTime;

        log.info("{} executed in {} ms", joinPoint.getSignature(), executionTime);

        return result;
    }
}
相关推荐
Morpheon3 分钟前
R语言非结构化文本挖掘入门指南
开发语言·r语言
码不停蹄的玄黓22 分钟前
JUC核心解析系列(五)——执行框架(Executor Framework)深度解析
java·jvm·spring boot·spring cloud
白总Server23 分钟前
GaussDB 分布式数据库调优(架构到全链路优化)
java·网络·c++·架构·go·scala·数据库架构
listhi52040 分钟前
k8s使用私有harbor镜像源
java·docker·kubernetes
在未来等你1 小时前
Java并发编程实战 Day 21:分布式并发控制
java·多线程·并发编程
程序员小假1 小时前
你会不会使用 SpringBoot 整合 Flowable 快速实现工作流呢?
java·后端
CPETW1 小时前
同旺科技 USB TO SPI / I2C适配器(专业版)--EEPROM读写——C
c语言·开发语言·科技·stm32·单片机·嵌入式硬件·电子
来自外太空的鱼-张小张1 小时前
java将pdf文件转换为图片工具类
java·python·pdf
代码中の快捷键1 小时前
如何实现一个登录功能?
java·开发语言
虾球xz1 小时前
CppCon 2015 学习:C++ devirtualization in clang
开发语言·c++·学习