首页天道酬勤spring注解解析流程(spring注解源码解析)

spring注解解析流程(spring注解源码解析)

admin 12-04 16:23 403次浏览

00-1010 Annotation是JDK1.5引入的一种机制,它使用@interface的定义,以@ [annotation name]的格式引用一个注释。

注释可以传递参数,并且可以应用于类、变量、方法、参数等。

00-

基础知识

元注解

@Target标识注释的范围。具体值是ElementType类型的枚举变量。

//注释的范围

公共枚举元素类型(

TYPE,//作用于类、接口(包括注释类型)和枚举。

FIELD,//作用于变量(包括枚举常数)

方法,//方法

参数,//参数

CONSTRUCTOR,//constructor

LOCAL_VARIABLE,//局部变量

ANNOTATION_TYPE,//annotation type

PACKAGE,//package

TYPE_PARAMETER,//类型参数的声明

TYPE_USE,//包含TYPE和TYPE_PARAMETER,在使用TYPE的地方都可以使用。

模块//模块(JDK9中新增)

}

复制代码

@Target

@Retention表示注释的生命周期。注释有三个生命周期,在RetentionPolicy枚举中定义,即:

来源:仅在源代码中使用,不被编译器识别。CLASE:在类中有效,由编译器记录在类文件中,但在运行时不被虚拟机保留。Runtime:运行时有效,由编译器记录在类文件中,默认值为运行时class。一般来说,框架中使用的自定义注释和注释被设置为RUNTIME。

@Retention

表示注释将包含在Javadoc中。

00-1010意味着子类可以继承父类的注释。

@Document

表示注释可以重用。需要定义两个注释来使用重复的注释。

定义两个注释“宠物”和“宠物”,其中“宠物”注释表示“宠物”的容器,并包含一个类型为“宠物[]”的参数。

@Retention(保留策略。RUNTIME)

公共接口Pets {

pet[]value();

}

复制代码,在我们真正想要使用的重复注释Pet中,使用@Repeatable元注释,并将参数类型指定为Pet.class

@已记录

@可重复(宠物.类)

公共@宠物界面{

字符串值();

}

复制代码,然后您可以重用宠物。

@宠物('中国花园猫')

@宠物('哈士奇')

公共类编码器

//.

}

复制代码

@Inherited

@Override、@弃用、@SuppressWarnings等。都是可以直接使用的内置注释。

00-1010

@Repeatable

在理解了元注释之后,我们已经学会了如何定义一个简单的注释。让我们继续学习如何向注释添加更多功能。

00-1010注意:可以添加参数。参数的格式是:

[参数类型][参数名称]();

复制代码,使用注释时,必须为参数指定参数值。

@XXX([参数名]=[参数值])

复制代码如果参数名被定义为值,并且只有一个参数,则可以直接赋值,而无需声明参数名,就像我们上面定义的Pet一样。

00-1010注释参数可以使用default以下列格式指定默认值:

[参数类型][参数名称]()默认值[默认值];

复制代码。我们修改宠物注释,添加一个参数并指定默认值。

@做

cumented @Retention(RetentionPolicy.RUNTIME) @Inherited @Target({ElementType.TYPE}) public @interface Pet { String value(); String name() default "小可爱"; } 复制代码

使用时注意 value 必须显式地指明参数名,

@Pet(value = "中华田园猫",name = "花花") public class Coder{ // ... } 复制代码

总结

添加了默认值可以不指定参数值注解使用时参数顺序无关紧要只有一个参数时,如果参数名称为 value,使用时直接写参数值

解析注解

解析注解需要使用 反射。

反射与注解

反射在运行时借助反射 API 获取类(接口,注解)的任何内部信息,并且可以直接操作 内部属性 和 方法。

上述的所有可获取的信息都要通过一个 Class 对象来操作,获取 Class 对象的方式有以下几种:

通过类的 class 属性Class aClass = String.class; 复制代码通过对象的 getClass() 方法String str = new String(); Class aClass = str.getClass(); 复制代码通过 Class.forName() 方法Class aClass = Class.forName("com.zcat.example.annotation.MapValue"); 复制代码

该方法有一个 ClassNotFoundException。

如果是基本数据类型的包装类,可以通过 TYPE 属性获得。

Class aClass = Integer.TYPE; 复制代码

获得 Class 对象后,可以通过反射得到属性和方法等。与注解相关的方法有:

getAnnotations():获得注解列表getDeclaredAnnotation(Class aClass):获得指定类型的注解isAnnotationPresent(Class aClass):是否有指定类型的注解

解析自定义注解

我们模仿 SpringBoot 配置文件注入的注解 @Value,自定义一个注解 @MapValue 用来从 properties 配置文件中读取值注入到新建的对象 Coder 属性。

// MapValue.class @Retention(RetentionPolicy.RUNTIME) public @interface MapValue { String value(); } 复制代码

在 Coder 中定义两个属性,并使用注解标注

Coder 是一个 POJO 类,已省略 getter/setter 和 toString 方法。

// Coder.class public class Coder { @MapValue("coder.name") private String name; @MapValue("coder.lang") private String lang; public Coder() {} // ... } 复制代码

配置文件 application.properties 配置属性值。

# application.properties coder.name=zcats coder.lang=Java 复制代码

最后封装一个方法 getCoder() 获得一个 Coder 对象,隐藏主动的 new 操作。

首先要先读取配置文件的内容,

/** 读取配置文件 */ public static Properties loadConfig() { FileInputStream is = new FileInputStream(new File("C:\Users\afangor\Coding\Projects\corecoding\src\main\java\com\zcat\example\annotation\application.properties")); Properties config = new Properties(); config.load(is); return config; } 复制代码

然后利用反射机制 (getDeclaredFields()) 获取 Coder 的所有属性,遍历并判断属性上是否有 MapValue 注解。如果有,就使用 getAnnotation(Class aClass) 方法获取注解,读取注解的参数值,再到配置对象中获取配置的值,通过反射赋值给 Coder 对象。

// Method:getCoder(),获得 Coder 对象,自动注入配置的属性值 public static Coder getCoder() throws Exception { Properties config = loadConfig(); Coder coder = new Coder(); Field[] fields = coder.getClass().getDeclaredFields(); for(Field field : fields){ boolean exists = field.isAnnotationPresent(MapValue.class); if(exists){ MapValue annotation = field.getAnnotation(MapValue.class); field.setAccessible(true); field.set(coder,config.get(annotation.value())); } } return coder; } 复制代码

需要注意的是,由于 Coder 的属性是 private 的,所以设置属性值前,要先调用 field.setAccessible(true) 允许操作私有属性。

作者:大发猫耶链接:https://juejin.cn/post/6989485910404366372来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

create-react-appTypescript3.5Java0基础_day11-抽象类与接口
多线程和并发(一个进程可以有多个线程) ()
相关内容