java 解析带 和=_Java学习:元注解和注解的解析

在使用注解之前,需要了解:一、什么是注解?二、注解是如何产生作用的?而元注解是一个很好的切入点

元注解的源码结构

e9329c8a59c2

从java.lang.annotation包截图看,一共定义了6个注解:

@Document

@Target

@Retention

@Inherited

@Native

@Repeatable

其中前4个是元注解

元注解的定义

元注解负责注解自定义注解,你可以看到许多自定义的注解上面都有这些元注解:

例如spring mvc的注解@RequestMapping

@Target({ElementType.METHOD, ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Mapping

public @interface RequestMapping{

......

}

元注解的用途

@Target

标识注解的使用范围,可以赋值为ElementType类型,ElementType定义如下:

public enum ElementType {

/** Class, interface (including annotation type), or enum declaration */

TYPE,

/** Field declaration (includes enum constants) */

FIELD,

/** Method declaration */

METHOD,

/** Formal parameter declaration */

PARAMETER,

/** Constructor declaration */

CONSTRUCTOR,

/** Local variable declaration */

LOCAL_VARIABLE,

/** Annotation type declaration */

ANNOTATION_TYPE,

/** Package declaration */

PACKAGE,

/**

* Type parameter declaration

*

* @since 1.8

*/

TYPE_PARAMETER,

/**

* Use of a type

*

* @since 1.8

*/

TYPE_USE

}

仍然以@RequestMapping为例,它的@Target赋值为{ElementType.METHOD, ElementType.TYPE},参考Element注释可以理解@RequestMapping可以用于java的方法定义及Class/Interfac/enum的定义上

@Retention

可以赋值 RetentionPolicy类型,RetentionPolicy定义如下:

public enum RetentionPolicy {

/**

* Annotations are to be discarded by the compiler.

*/

SOURCE,

/**

* Annotations are to be recorded in the class file by the compiler

* but need not be retained by the VM at run time. This is the default

* behavior.

*/

CLASS,

/**

* Annotations are to be recorded in the class file by the compiler and

* retained by the VM at run time, so they may be read reflectively.

*

* @see java.lang.reflect.AnnotatedElement

*/

RUNTIME

}

RetentionPolicy.SOURCE:表明注解会被编译器丢弃,字节码中不会带有注解信息

RetentionPolicy.CLASS:表明注解会被写入字节码文件,且是@Retention的默认值

RetentionPolicy.RUNTIME:表明注解会被写入字节码文件,并且能够被JVM 在运行时获取到,可以通过反射的方式解析到

@Documented

/**

* Indicates that annotations with a type are to be documented by javadoc

* and similar tools by default. This type should be used to annotate the

* declarations of types whose annotations affect the use of annotated

* elements by their clients. If a type declaration is annotated with

* Documented, its annotations become part of the public API

* of the annotated elements.

*

* @author Joshua Bloch

* @since 1.5

*/

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public @interface Documented {

}

从注释可以看到 @Document注解用途主要是标识类型是否要被收入javadoc

如何处理注解?

jdk中是通过AnnotatedElement(package java.lang.reflect)接口实现对注解的解析,我们的Class类实现了AnnotatedElement接口

public final class Class implements java.io.Serializable,

GenericDeclaration,

Type,

AnnotatedElement {

......

}

AnnotatedElement代码:

e9329c8a59c2

AnnotatedElement的注释:

Represents an annotated element of the program currently running in this VM. This interface allows annotations to be read reflectively

翻译过来就是:AnnotatedElement代表了jvm中一个正在运行的被注解元素,这个接口允许通过反射的方式读取注解

可以看下Class类中对于AnnotatedElement接口都是如何实现的:

/**

* @throws NullPointerException {@inheritDoc}

* @since 1.5

*/

@SuppressWarnings("unchecked")

public A getAnnotation(Class annotationClass) {

Objects.requireNonNull(annotationClass);

return (A) annotationData().annotations.get(annotationClass);

}

/**

* {@inheritDoc}

* @throws NullPointerException {@inheritDoc}

* @since 1.5

*/

@Override

public boolean isAnnotationPresent(Class extends Annotation> annotationClass) {

return GenericDeclaration.super.isAnnotationPresent(annotationClass);

}

/**

* @throws NullPointerException {@inheritDoc}

* @since 1.8

*/

@Override

public A[] getAnnotationsByType(Class annotationClass) {

Objects.requireNonNull(annotationClass);

AnnotationData annotationData = annotationData();

return AnnotationSupport.getAssociatedAnnotations(annotationData.declaredAnnotations,

this,

annotationClass);

}

/**

* @since 1.5

*/

public Annotation[] getAnnotations() {

return AnnotationParser.toArray(annotationData().annotations);

}

/**

* @throws NullPointerException {@inheritDoc}

* @since 1.8

*/

@Override

@SuppressWarnings("unchecked")

public A getDeclaredAnnotation(Class annotationClass) {

Objects.requireNonNull(annotationClass);

return (A) annotationData().declaredAnnotations.get(annotationClass);

}

/**

* @throws NullPointerException {@inheritDoc}

* @since 1.8

*/

@Override

public A[] getDeclaredAnnotationsByType(Class annotationClass) {

Objects.requireNonNull(annotationClass);

return AnnotationSupport.getDirectlyAndIndirectlyPresent(annotationData().declaredAnnotations,

annotationClass);

}

/**

* @since 1.5

*/

public Annotation[] getDeclaredAnnotations() {

return AnnotationParser.toArray(annotationData().declaredAnnotations);

}

上面的接口实现中,大致的原理都是一致的,我们挑选其中的getAnnotation方法来讲解:

getAnnotation

根据注解的class实例从类的注解缓存数据中获取匹配的注解类型

Controller是注解类型,Controller.getClass()获取到的就是Class实例

1、代码中annotationData().annotations是一个Map(key为注解的Class实例,value为注解类型),源码为:

// annotation data that might get invalidated when JVM TI RedefineClasses() is called

private static class AnnotationData {

final Map, Annotation> annotations;

final Map, Annotation> declaredAnnotations;

// Value of classRedefinedCount when we created this AnnotationData instance

final int redefinedCount;

AnnotationData(Map, Annotation> annotations,

Map, Annotation> declaredAnnotations,

int redefinedCount) {

this.annotations = annotations;

this.declaredAnnotations = declaredAnnotations;

this.redefinedCount = redefinedCount;

}

}

2、annotationData()的源码是:

private AnnotationData annotationData() {

while (true) { // retry loop

AnnotationData annotationData = this.annotationData;

int classRedefinedCount = this.classRedefinedCount;

if (annotationData != null &&

annotationData.redefinedCount == classRedefinedCount) {

return annotationData;

}

// null or stale annotationData -> optimistically create new instance

AnnotationData newAnnotationData = createAnnotationData(classRedefinedCount);

// try to install it

if (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) {

// successfully installed new AnnotationData

return newAnnotationData;

}

}

}

核心的逻辑是:当this.annotationData为空,解析类中的annotationData并写入this.annotationData,最后都会返回this.annotationData

3、其中Atomic.casAnnotationData(this, annotationData, newAnnotationData)的作用便是将解析到的annotationData写入this.annotationData:

static boolean casAnnotationData(Class> clazz,

AnnotationData oldData,

AnnotationData newData) {

return unsafe.compareAndSwapObject(clazz, annotationDataOffset, oldData, newData);

}

其中unsafe.compareAndSwapObject是一个native方法

4、而createAnnotationData(classRedefinedCount)的作用是解析类中用到的annotationData

private AnnotationData createAnnotationData(int classRedefinedCount) {

Map, Annotation> declaredAnnotations =

AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this);

Class> superClass = getSuperclass();

Map, Annotation> annotations = null;

if (superClass != null) {

Map, Annotation> superAnnotations =

superClass.annotationData().annotations;

for (Map.Entry, Annotation> e : superAnnotations.entrySet()) {

Class extends Annotation> annotationClass = e.getKey();

if (AnnotationType.getInstance(annotationClass).isInherited()) {

if (annotations == null) { // lazy construction

annotations = new LinkedHashMap<>((Math.max(

declaredAnnotations.size(),

Math.min(12, declaredAnnotations.size() + superAnnotations.size())

) * 4 + 2) / 3

);

}

annotations.put(annotationClass, e.getValue());

}

}

}

if (annotations == null) {

// no inherited annotations -> share the Map with declaredAnnotations

annotations = declaredAnnotations;

} else {

// at least one inherited annotation -> declared may override inherited

annotations.putAll(declaredAnnotations);

}

return new AnnotationData(annotations, declaredAnnotations, classRedefinedCount);

}

整个的处理逻辑是:

1、获取类本身的declaredAnnotations

2、获取父类的annotations

3、将declaredAnnotations+annotations整合,返回

Annotation解析的范例代码:

@Component

public class SSHClient {

......

}

public class AnnotationHelper {

public static void main(String[] args) {

Annotation[] annotations = new Annotation[0];

annotations = SSHClient.class.getAnnotations();

for (Annotation annotation : annotations) {

System.out.println(annotation.toString());

System.out.println(annotation.annotationType());

System.out.println(annotation.getClass().getName());

System.out.println(annotation.getClass().getTypeName());

System.out.println(annotation.getClass().toString());

}

if (SSHClient.class.isAnnotationPresent(Component.class)) {

System.out.println("find Component annotation");

}

Annotation annotation = SSHClient.class.getAnnotation(Component.class);

System.out.println(annotation.toString());

System.out.println(annotation.annotationType());

System.out.println(annotation.getClass().getName());

System.out.println(annotation.getClass().getTypeName());

System.out.println(annotation.getClass().toString());

}

}

执行结果:

e9329c8a59c2

可以看到,通过Annotation接口中定义的annotationType()可以获取Annotation的类型

实际应用中,比如spring框架中对注解的解析有专门的工具类,但是都是基于AnnotatedElement中定义的方法来实现的

以上,就是整个元注解和注解解析相关的讲解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值