写点什么

我看 JAVA 之 Annotation

用户头像
awen
关注
发布于: 2021 年 02 月 27 日

我看 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()); } }}
复制代码



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


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


用户头像

awen

关注

Things happen for a reason. 2019.11.15 加入

还未添加个人简介

评论

发布
暂无评论
我看JAVA 之 Annotation