美文网首页
注解的基本原理

注解的基本原理

作者: 打工养老板 | 来源:发表于2019-10-18 15:01 被阅读0次
    一个注解准确意义上来说,只不过是一种特殊的注释而已,如果没有解析它的代码,它可能连注释都不如。

    [java.lang.annotation]中描述到

    The common interface extended by all annotation types.
    (所有的注解类型都继承自这个普通的接口(Annotation))

    内置的注解

    Java 定义了一套注解,共有 8 个,4 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。

    作用在代码的注解是

    • @Override - 检查该方法是否是重载方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
    • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
    • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

    作用在其他注解的注解(或者说 元注解)是:

    • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
    • @Documented - 标记这些注解是否包含在用户文档中。
    • @Target - 标记这个注解应该是哪种 Java 成员。
    • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

    从 Java 7 开始,额外添加了 3 个注解:

    • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
    • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
    • @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
    • @Native - Java 8 开始支持,标识用原生代码定义一个静态变量
    Annotation 组成部分
    package java.lang.annotation;
    public interface Annotation {
    
        boolean equals(Object obj);
        int hashCode();
        String toString();
        Class<? extends Annotation> annotationType();
    }
    
    package java.lang.annotation;
    public enum ElementType {
        TYPE,               /* 类、接口(包括注释类型)或枚举声明  */
        FIELD,              /* 字段声明(包括枚举常量)  */
        METHOD,             /* 方法声明  */
        PARAMETER,          /* 参数声明  */
        CONSTRUCTOR,        /* 构造方法声明  */
        LOCAL_VARIABLE,     /* 局部变量声明  */
        ANNOTATION_TYPE,    /* 注释类型声明  */
        PACKAGE             /* 包声明  */
    }
    
    package java.lang.annotation;
    public enum RetentionPolicy {
        SOURCE,            /* Annotation信息仅存在于编译器处理期间,编译器处理完之后就没有该Annotation信息了  */
        CLASS,             /* 编译器将Annotation存储于类对应的.class文件中。默认行为  */
        RUNTIME            /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */
    }
    

    Java自带的注解

    /**
    * 只能标注方法,表示该方法覆盖父类中的方法。
    **/
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    /**
    * 所标注内容,不再被建议使用。
    **/
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Deprecated {
    }
    /**
    * 所标注内容产生的警告,编译器会对这些警告保持静默。
    **/
    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
        String[] value();
    }
    /**
    * 忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
    **/
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
    public @interface SafeVarargs {}
    /**
    * 标识一个匿名函数或函数式接口。
    **/
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface FunctionalInterface {}
    /**
    * 只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。
    **/
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
        RetentionPolicy value();
    }
    /**
    * 只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性。
    **/
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Inherited {
    }
    /**
    * 所标注内容,可以出现在javadoc中。
    **/
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Documented {
    }
    /**
    * 只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。
    **/
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        ElementType[] value();
    }
    /**
    * 标识某注解可以在同一个声明上使用多次。
    **/
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Repeatable {
        Class<? extends Annotation> value();
    }
    /**
    * 标识用原生代码定义一个静态变量
    **/
    @Documented
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Native {
    }
    

    配合反射使用注解

    public class AnnotationTest {
        public static void main(String[] args) throws Exception {
    
            // 新建Person
            Person person = new Person();
            // 获取Person的Class实例
            Class<Person> c = Person.class;
            // 获取 somebody() 方法的Method实例
            Method mSomebody = c.getMethod("somebody", new Class[]{String.class, int.class});
            // 执行该方法
            mSomebody.invoke(person, new Object[]{"lily", 18});
            iteratorAnnotations(mSomebody);
    
            // 获取 somebody() 方法的Method实例
            Method mEmpty = c.getMethod("empty", new Class[]{});
            // 执行该方法
            mEmpty.invoke(person, new Object[]{});
            iteratorAnnotations(mEmpty);
        }
        public static void iteratorAnnotations(Method method) {
    
            // 判断 somebody() 方法是否包含MyAnnotation注解
            if(method.isAnnotationPresent(MyAnnotation.class)){
                // 获取该方法的MyAnnotation注解实例
                MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
                // 获取 myAnnotation的值,并打印出来
                String[] values = myAnnotation.value();
                for (String str:values)
                    System.out.printf(str+", ");
                System.out.println();
            }
    
            // 获取方法上的所有注解,并打印出来
            Annotation[] annotations = method.getAnnotations();
            for(Annotation annotation : annotations){
                System.out.println(annotation);
            }
        }
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation {
        String[] value() default "unknown";
    }
    
    class Person {
        @MyAnnotation
        @Deprecated
        public void empty(){
            System.out.println("\nempty");
        }
    
        @MyAnnotation(value={"girl","boy"})
        public void somebody(String name, int age){
            System.out.println("\nsomebody: "+name+", "+age);
        }
    }
    
    配合spring aspect切面做日志
    package com.*.annotation;
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Log {
    
        String value() default "";
    }
    
    @Aspect
    @Component
    public class LogAspect {
        //路劲自己写
        @Pointcut("@annotation(com.**.annotation.Log)")
        public void logPointCut() { 
            
        }
    
        @Around("logPointCut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            long beginTime = System.currentTimeMillis();
            //执行方法
            Object result = point.proceed();
            //执行时长(毫秒)
            long time = System.currentTimeMillis() - beginTime;
    
            //打印日志
            printLog(point, time);
    
            return result;
        }
    
        private void printLog(ProceedingJoinPoint joinPoint, long time) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
    
            Log log = method.getAnnotation(Log.class);
            if(log != null){
                //注解上的描述 
                System.out.println("描述:" + log.value());
            }
    
            //请求的方法名
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = signature.getName();
            System.out.println("方法名:" + className + "." + methodName + "()");
    
            //请求的参数
            Object[] args = joinPoint.getArgs();
            try{
                String params = new Gson().toJson(args);
                System.out.println("参数:" + params);
            }catch (Exception e){
                e.printStackTrace();
            }
                System.out.println("消耗时间:" + time);
        }
    }
    

    腾讯云双十一优惠链接

    相关文章

      网友评论

          本文标题:注解的基本原理

          本文链接:https://www.haomeiwen.com/subject/dcrimctx.html