我看JAVA 之 Annotation-阿里云开发者社区

开发者社区> 开发与运维> 正文
登录阅读全文

我看JAVA 之 Annotation

简介:

我看JAVA 之 Annotation

注:基于jdk11

注解包结构

_2020_04_20_2_55_35

名词解释:

  • meta-annotation 元数据注解 表示用来声明注解的注解
  • marker-annotation 标记注解 表示没有成员的注解

Annotation

    
Annotation 是一个被所有注解类型实现的通用接口。但是如果硬编码实现此接口不能定义一个注解类型,同时,此接口本身也不是一个注解类型。 
所有注解声明格式为: @interface annotationName{    } 隐式表明某个类型(注解类型)实现了接口java.lang.annotation.Annotation
public interface Annotation {

    boolean equals(Object obj);

    int hashCode();

    String toString();

    Class<? extends Annotation> annotationType();
}

Target

meta-annotation,表示某注解类型应用在哪些语法元素上,默认应用在除TYPE外的所有语法元素上。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

ElementType

枚举类型 表示某注解可以应用的元素上下文。
public enum ElementType {
    TYPE,
    FIELD,
    METHOD,
    PARAMETER,
    CONSTRUCTOR,
    LOCAL_VARIABLE,
    ANNOTATION_TYPE,
    PACKAGE,

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

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

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

Retention

meta-annotation 表示注解类型持有范围或生命周期。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

RetentionPolicy

枚举类型 表示持有注解周期策略。
public enum RetentionPolicy { 
    SOURCE,//应用在源文件上,主要做编译时检查,检查完毕即丢弃。 
    CLASS,//默认值,被编译器记录在字节码文件中,但不能被运行时持有。 
    RUNTIME//除了可以被编译器记录在字节码文件中,还可以被运行时持有。参见:java.lang.reflect. AnnotatedElement(表示运行在VM的程序中的可以被注解或注解了的元素) 
} 

Inherited

meta-annotation 同时也是marker-annotation 表示某个注解类型是可以被继承的 

Documented

meta-annotation 同时也是marker-annotation 表示某个类型标记@Documented注解,那么此类型上所有注解会被JAVA Doc收集为API一部分 

Native

meta-annotation 同时也是marker-annotation(since1.8),表明一个字段引用的值可能来自于本地代码

Repeatable

meta-annotation(since1.8)

异常

AnnotationFormatError
AnnotationTypeMismatchException
IncompleteAnnotationException

内部原理

以实现一个简单的orm注解的形式来描述Java的Annotation的内部原理,代码如下:

源代码

package chapter04;

import java.lang.annotation.*;

/**
 * a orm's table annotation
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {

  String name() default "";
  String alias() default "";
}
package chapter04;

import java.lang.annotation.*;

/**
 * a orm's column annotation
 */
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    boolean primary() default false;
    String name() default "";
    String type() default "varchar";
    int length() default  0;
    String alias() default "";
}
package chapter04;

@Table(name = "t_student", alias = "s")
public class Student {

    @Column(primary = true, name = "_id", type = "bigint", length = 20)
    String id;
    @Column(name = "name", type = "string", length = 32)
    String name;
}
package chapter04;


public class TestAnno {

    public static void main(String [] args) throws NoSuchFieldException {

        System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

        Table table = Student.class.getAnnotation(Table.class);
        System.out.printf("table'name is %s, alias is %s. \n", table.name(), table.alias());

        Column column = Student.class.getDeclaredField("id").getAnnotation(Column.class);
        System.out.printf("column'name is %s, alias is %s. \n", column.name(), column.alias());

    }
}

通过设置环境变量,可以保存jdk动态生成的代码,查看java.lang.reflect.ProxyGenerator类中的配置, 如下:

 /** debugging flag for saving generated class files */
    private static final boolean saveGeneratedFiles =
        java.security.AccessController.doPrivileged(
            new GetBooleanAction(
                "jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue();

jdk生成的代理代码

package com.sun.proxy;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Retention {
    private static Method m1;
    private static Method m2;
    private static Method m4;
    private static Method m0;
    private static Method m3;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class annotationType() throws  {
        try {
            return (Class)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final RetentionPolicy value() throws  {
        try {
            return (RetentionPolicy)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("java.lang.annotation.Retention").getMethod("annotationType");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m3 = Class.forName("java.lang.annotation.Retention").getMethod("value");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
package com.sun.proxy;

import chapter04.Table;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy1 extends Proxy implements Table {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m5;
    private static Method m4;
    private static Method m0;

    public $Proxy1(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String name() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class annotationType() throws  {
        try {
            return (Class)super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String alias() throws  {
        try {
            return (String)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("chapter04.Table").getMethod("name");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m5 = Class.forName("chapter04.Table").getMethod("annotationType");
            m4 = Class.forName("chapter04.Table").getMethod("alias");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
package com.sun.proxy;

import chapter04.Column;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy2 extends Proxy implements Column {
    private static Method m1;
    private static Method m7;
    private static Method m3;
    private static Method m4;
    private static Method m2;
    private static Method m8;
    private static Method m5;
    private static Method m6;
    private static Method m0;

    public $Proxy2(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final boolean primary() throws  {
        try {
            return (Boolean)super.h.invoke(this, m7, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String name() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String type() throws  {
        try {
            return (String)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class annotationType() throws  {
        try {
            return (Class)super.h.invoke(this, m8, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int length() throws  {
        try {
            return (Integer)super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String alias() throws  {
        try {
            return (String)super.h.invoke(this, m6, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m7 = Class.forName("chapter04.Column").getMethod("primary");
            m3 = Class.forName("chapter04.Column").getMethod("name");
            m4 = Class.forName("chapter04.Column").getMethod("type");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m8 = Class.forName("chapter04.Column").getMethod("annotationType");
            m5 = Class.forName("chapter04.Column").getMethod("length");
            m6 = Class.forName("chapter04.Column").getMethod("alias");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

_2020_05_06_4_55_24


如上图,debug运行TestAnno,结合jdk动态生成的代理类可以得出如下结论:


Table、Column是实现了Annotation的特殊接口,而通过反射获取注解返回的是Java运行时生成的动态代理对象$Proxy1(Table的实现类)、$Proxy2(Column实现类)

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章