在使用spring框架的时候,会提供很多注解例如 @Autowired、@Bean等。Spring 通过扫描注解,在标注了过注解的地方会执行特定操作。如实例化Bean,注入Bean。所以注解的用法已经比较清楚,接下来开始实战:
先看看别人定义的注解:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
@AliasFor(
annotation = Controller.class
)
String value() default "";
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
}
@Target:定义注解可以标注的范围,选项参考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
}
@Retention:定义注解的生命周期,选项参考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
}
生命周期的大小 SOURCE < CLASS < RUNTIME
SOURCE:在源码中保留,编译时无效。(检测代码是否正确可用)
CLASS:编译有效,JVM加载时无效。(编译时做预处理可用)
RUNTIME:JVM加载运行时仍然有效。(运行时可用)
@Documented:生成文档是如果使用该注解修饰的,被标注的元素的API文档中将会包含该注解说明。
@Inherited:在标注的注解会被继承获取。如果A是B的父类,A使用了@Inherited注解。Class<B>调用getAnnotations()的时候,会获取Class<A>标记的注解,如果未使用@Inherited注解不获取。
有了基本的理论知识开始测试:
1、定义一个annotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface FirstAnnotation {
/**
* 定义一个枚举类型
*/
ModelEnum type() default ModelEnum.B;
/**
* 定义一个枚举数组类型
*/
ModelEnum[] types() default {};
/*
* 定义一个数字类型
*/
int id() default 99;
/**
* 定义一个数字数组类型
*/
int[] ids() default {};
/*
* 定义一个字符类型
*/
String name() default "";
/*
* 定义一个字符数组类型
*/
String[] names() default {};
}
public enum ModelEnum {
A,
B,
C
}
public class Model {
@FirstAnnotation(ids = {1, 2, 3, 4, 5}, types = {ModelEnum.A, ModelEnum.B})
public String field1;
}
编写测试类
public class Test {
public static void main(String[] args) throws Exception {
Class<Model> modelClass = Model.class;
// 获取字段1
Field field1 = modelClass.getField("field1");
FirstAnnotation firstAnnotation = field1.getAnnotation(FirstAnnotation.class);
System.out.println(firstAnnotation.id());
for (int id : firstAnnotation.ids()) {
System.out.print(id + "\t");
}
System.out.println(firstAnnotation.name());
for (String name : firstAnnotation.names()) {
System.out.print(name + "\t");
}
System.out.println(firstAnnotation.type());
for (ModelEnum modelEnum : firstAnnotation.types()) {
System.out.print(modelEnum.name() + "\t");
}
}
}
打印结果:
99
1 2 3 4 5
B
A B
经过测试已经完成了自定义注解。
接下来测试@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InheritableAnnotation {
}
@InheritableAnnotation
public class ModelParent {
private String f1;
}
// 继承ModelParent
public class Model extends ModelParent {
...
}
public class Test {
public static void main(String[] args) throws Exception {
Class<Model> modelClass = Model.class;
// 获取class注解
Annotation[] annotations = modelClass.getAnnotations();
for (Annotation annotation : annotations) {
String name = annotation.annotationType().getName();
System.out.println(name);
}
}
}
打印结果:
com.pss.annotation.InheritableAnnotation
再删除@Inherited 测试
打印结果: