springboot自定义注解分析及应用

一、简介

  • 注解:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
  • 作用分类:
    ①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
    ②代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
    ③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
  • 自定义注解:使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。规定注解里面只能使用java八大基本数据类型和String、enum、Annotation、class。
  • 自定义注解格式:public @interface 注解名 {定义体}

二、原理

  注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

三、元注解

 4种元注解:@Target @Retention @Documented @Inherited

  • @Target
    @Target(ElementType.TYPE) //用于Class, interface (including annotation type), or enum
    @Target(ElementType.FIELD) //用于Field (includes enum constants)
    @Target(ElementType.METHOD) //用于Method
    @Target(ElementType.PARAMETER) //用于Formal parameter正式参数
    @Target(ElementType.CONSTRUCTOR) //用于Constructor方法
    @Target(ElementType.LOCAL_VARIABLE) //用于局部变量
    @Target(ElementType.ANNOTATION_TYPE) //用于注释类型
    @Target(ElementType.PACKAGE) //用于Package
    @Target(ElementType.TYPE_PARAMETER) //ype parameter declaration用于类型参数(@since jdk1.8)
    @Target(ElementType.TYPE_USE) //Use of a type使用类型(@since jdk1.8)
  • @Retention
    @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
    @Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
    @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
  • @Document:该注解将被包含在javadoc中
  • @Inherited:子类可以继承父类中的该注解

四、实例:自定义注解的实现打印日志

  1. 导入aop相关jar包

    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-aop</artifactId>
    		</dependency>
    
  2. 定义注解接口

    import java.lang.annotation.*;
    
    @Documented //注解是否将包含在JavaDoc中
    @Target(ElementType.METHOD) //注解用于什么地方
    @Retention(RetentionPolicy.RUNTIME) //定义该注解的生命周期
    public @interface LogAnnotation {
    }
    
  3. 配置aop拦截切面类

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    import java.util.Arrays;
    import java.util.Date;
    
    @Component
    @Aspect
    public class LogAspect {
    
        //切入点签名
        @Pointcut("@annotation(com.cloud.ribbon.consumer.annotation.LogAnnotation)")
        private void cutPoint() {
    
        }
        //前置通知
        @Before("cutPoint()")
        public void beforeCutPoint() {
        }
    
        //环绕通知
        @Around(value = "cutPoint()")
        public Object intercept(ProceedingJoinPoint joinPoint) {
            Object result = null;
            //类名
            String calssName = joinPoint.getTarget().getClass().getName();
            System.out.println("类名:" + calssName);
            //方法名
            String methodName = joinPoint.getSignature().getName();
            System.out.println("方法名:" + methodName);
            //参数
            Object[] args = joinPoint.getArgs();
            System.out.println("参数:" + Arrays.asList(args).toString());
            //方法开始时间
            Date date = new Date();
            System.out.println("方法开始时间:" + date);
            //方法返回值
            try {
                result = joinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            System.out.println("方法返回值:" + result);
            if (result.toString().contains("bbb")){
                result = "修改后的值bbbbb";
            }
            System.out.println("方法修改后的返回值:" + result);
            //方法结束时间
            Date date2 = new Date();
            System.out.println("方法结束时间:" + date2);
            return result;
        }
    
        //后置通知
        @After("cutPoint()")
        public void afterCutPoint() {
        }
    }
    
  4. 使用注解

    import com.cloud.ribbon.consumer.annotation.LogAnnotation;
    import com.cloud.ribbon.consumer.service.HelloService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class ConsumerController {
        @Autowired
        HelloService helloService;
    
        @LogAnnotation
        @GetMapping(value = "/index")
        public String index() {
            return helloService.sayHello()+ "bbbbbb";
        }
    }
    
  5. 控制台输出结果

    方法名:index
    参数:[]
    方法开始时间:Tue Dec 24 15:42:19 CST 2019
    方法返回值:查询失败bbbbbb
    方法修改后的返回值:修改后的值bbbbb
    方法结束时间:Tue Dec 24 15:42:20 CST 2019
    

备注:service层代码没有贴上来,可根据自己实际情况使用注解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值