开发者

详解SpringBoot如何自定义注解

目录
  • 1.什么是注解
    • 元注解
    • @Target
    • @Retention
    • @Repeatable
    • @Inherited
  • 2.代码工程
    • 实验目的
    • pom.XML
    • controller
    • custom annotation
    • 代码仓库
  • 3.测试

    1.什么是注解

    注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

    元注解

    有一些注解可以修饰其他注解,这些注解就称为元注解(meta annotation)。Java标准库已经定义了一些元注解,我们只需要使用元注解,通常不需要自己去ouOLzJn编写元注解。

    @Target

    最常用的元注解是@Target。使用@Target可以定义Annotation能够被应用于源码的哪些位置:

    • 类或接口:ElementType.TYPE
    • 字段:ElementType.FIELD
    • 方法:ElementType.METHOD
    • 构造方法:ElementType.CONSTRUCTOR
    • 方法参数:ElementType.PARAMETER

    例如,定义注解@Report可用在方法上,我们必须添加一个@Target(ElementType.METHOD)

    @Target(ElementType.METHOD)
    public @interface Report {
        int type() default 0;
        String level() default "info";
        String value() default "";
    }
    

    定义注解@Report可用在方法或字段上,可以把@Target注解参数变为数组{ ElementType.METHOD, ElementType.FIELD }

    @Target({
        ElementType.METHOD,
        ElementType.FIELD
    })
    public @intphperface Report {
        ...
    }
    

    实际上@Target定义的valueElementType[]数组,只有一个元素时,可以省略数组的写法。

    @Retention

    另一个重要的元注解@Retention定义了Annotation的生命周期:

    • 仅编译期:RetentionPolicy.SOURCE
    • 仅class文件:RetentionPolicy.CLASS
    • 运行期:RetentionPolicy.RUNTIME

    如果@Retention不存在,则该Annotation默认为CLASS。因为通常我们自定义的Annotation都是RUNTIME,所以,务必要加上@Retention(RetentionPolicy.RUNTIME)这个元注解:

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Report {
        int type() default 0;
        String level() default "info";
        String value() default "";
    }
    

    @Repeatable

    使用@Repeatable这个元注解可以定义Annotation是否可重复。这个注解应用不是特别广泛。

    @Repeatable(Reports.class)
    @Target(ElementType.TYPE)
    public @interface Report {
        int type() default 0;
        String level() default "info";
        String value() default "";
    }
    
    @Target(ElementType.TYPE)
    public @interface Reports {
        Report[] value();
    }
    

    经过@Repeatable修饰后,在某个类型声明处,就可以添加多个@Report注解:

    @Report(type=1, level="debug")
    @Report(type=2, level="warning")
    public class Hello {
    }
    

    @Inherited

    使用@Inherited定义子类是否可继承父类定义的Annotation@Inherited仅针对@Target(ElementType.TYPE)类型的annotation有效,并且仅针对class的继承,对interface的继承无效:

    @Inherited
    @Target(ElementType.TYPE)
    public @interface Report {
        int type() default 0;
        String level() default "info";
        String value() default "";
    }
    

    在使用的时候,如果一个类用到了@Report

    @Report(type=1)
    public class Person {
    }
    

    则它的子类默认也定义了该注解:

    public class Student extends Person {
    }
    

    2.代码工程

    实验目的

    实现统计方法执行时间的注解

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>springboot-demo</artifactId>
            <groupId>com.et</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>annotations</artifactId>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
             php   <artifactId>spring-boot-autoconfigure</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test<编程客栈/scope>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
            <dependency>
                <groupId>org.ASPectj</groupId>
                <artifactId>aspectjweaver</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.assertj</groupId>
                <artifactId>assertj-core</artifactId>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
            </dependency>
    
            <!-- fastjson -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.21</version>
            </dependency>
        </dependencies>
    </project>
    

    controller

    使用自定义注解@RequestTime

    package com.et.annotation.controller;
    
    import com.et.annotation.RequestTime;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @RestController
    public class HelloWorldController {
        @RequestMapping("/hello")
       @RequestTime
        public Map<String, Object> showHelloWorld(){
            Map<String, Object> map = new HashMap<>();
            map.put("msg", "HelloWorld");
            return map;
        }
    }
    

    custom annotaphption

    自定义@RequestTime注解

    package com.et.annotation;
    
    import java.lang.annotation.*;
    
    /**
     * computa the excute time for the method
     */
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface RequestTime {
    
    }
    

    具体的拦截逻辑类

    package com.et.annotation;
    
    import com.et.annotation.util.AspectUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Method;
    
    
    @Slf4j
    @Aspect
    @Component
    public class RequestTimeAspect {
    
    
    
        @Pointcut(value = "@annotation(com.et.annotation.RequestTime)")
        public void pointcut() {
        }
    
        @Around("pointcut()")
        public Object handle(ProceedingJoinPoint point) throws Throwable {
          Method currentMethod = AspectUtil.getMethod(point);
          long starttime = System.currentTimeMillis();
          Object result = point.proceed();
          long endtime = System.currentTimeMillis();
          long requesttime =endtime-starttime;
          //if(requesttime>1000){
          log.info(AspectUtil.getClassName(point)+"."+currentMethod.getName()+"execute time:"+requesttime+" ms");
          //}
            return result;
        }
    }
    

    以上只是一些关键代码,所有代码请参见下面代码仓库

    代码仓库

    • https://github.com/Harries/springboot-demo(annotations)

    3.测试

    • 启动Spring Boot应用程序

    • 访问http://127.0.0.1:8088/hello

    • 控制台输出 日志

      2024-08-10 19:30:43.670 INFO 3343 --- [nio-8088-exec-1] com.et.annotation.RequestTimeAspect : com_et_annotation_controller_HelloWorldController.showHelloWorldexecute time:41 ms

    以上就是详解SpringBoot如何自定义注解的详细内容,更多关于SpringBoot自定义注解的资料请关注编程客栈(www.devze.com)其它相关文章!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜