Java元注解 - 生命周期 @Retention
2021-07-15 22:05
标签:简洁 必须 运行 tde 就是 cal ORC 项目 i++ 元注解的生命周期有三种,枚举定义在RetentionPolicy中,分别是SOURCE、CLASS和RUNTIME。 RetentionPolic.SOURCE一般的开发者很少用到,举几个Java自带的使用场景。 看到了吗,这些注解只是在编译的时候用到,一旦编译完成后,运行时没有任何意义,所以他们被称作源码级别注解。有过代码自动生成经验的开发者,譬如lombok开发者,都知道它是通过注解在编译时自动生成一部分代码,让源码看起来更简洁,字节码却很强大。当然,这种方式有它自身的缺陷,譬如不一致性,问题排解时的困扰,以及依赖问题,在此不展开讨论。 同样的原因,RetentionPolic.CLASS虽然作为注解的默认周期定义,也不是普通开发者自定义注解的首选,CLASS类型比起SOURCE和RUNTIME要更难理解些,因为通常开发者对编译前和运行时理解没有障碍,但是编译之后的字节码保留了元注解,又不能在运行时用到,这期间到底有什么用? 我们看个Spring-boot的例子。 Springboot针对config元数据处理器(ConfigurationMetadataAnnotationProcessor),是通过MetaCollector收集的,然后用MetaStore存在META-INF/spring-configuration-metadata.json。我们先不讨论Spring为何要这么做,有什么好处,感兴趣的可以自己去读源码,此刻我们关注的是RetentionPolic.CLASS,和这个实现有什么关系。ConfigurationMetadataAnnotationProcessor实现了Processor接口,而Processor接口,则是专门用来处理元注解的,故名注解处理器。注解处理器,可以帮助我们从字节码层面,做些听起来很奇怪的事儿,譬如信息收集、字节码重构、字节码自动生成等。如果真用到这个层面,那么要恭喜你,因为你已经超过了大部分的Java开发者,至少你对asm有一定的了解,知道类的结构定义ClassNode,知道如何读取它们Cla***eader。 小节下: Java元注解 - 生命周期 @Retention 标签:简洁 必须 运行 tde 就是 cal ORC 项目 i++ 原文地址:http://blog.51cto.com/10705830/2164430@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CallerServiceValidator {
String value() default "";
Class> validatorClass() default DEFAULT.class;
final class DEFAULT {}
}
元注解生命周期@Retention
自定义元注解时,绝大多数开发者(除非你是下面两种场景的使用者)都是使用RUNTIME,这个很好理解,我们期望在程序运行时,能够获取到这些注解,并干点有意思的事儿,而只有RetentionPolic.RUNTIME,能确保自定义的注解在运行时依然可见。举个例子,在spring项目启动后,获取所有或者部分可用接口的定义并列出来:try {
String basePath = "";
RequestMapping baseRequestMapping = AnnotationUtils.findAnnotation(bean.getClass(), RequestMapping.class);
if (baseRequestMapping != null) {
basePath = StringUtils.join(baseRequestMapping.path());
}
Method[] methods = ReflectionUtils.getAllDeclaredMethods(AopUtils.getTargetClass(bean));
if (methods != null) {
beanMetas = new CopyOnWriteArrayList();
for (Method method : methods) {
try {
RequestMapping methodRequestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
ApiIgnore apiIgnore = AnnotationUtils.findAnnotation(method, ApiIgnore.class);
if (methodRequestMapping != null && (apiIgnore == null || !apiIgnore.value())) {
PlatformApiMeta platformApiMeta = new PlatformApiMeta(AopUtils.getTargetClass(bean).getName(),
method.getName(), basePath + StringUtils.join(methodRequestMapping.path()));
RequestMethod[] httpMethods = methodRequestMapping.method();
if (httpMethods != null && httpMethods.length > 0) {
String[] httpMethodArr = new String[httpMethods.length];
for (int i = 0; i
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
SOURCE是源码级别的注解,仅在编译时使用;
CLASS是字节码级别的注解,大多也是在编译时使用;
RUNTIME才是我们的亲朋好友,运行时可见的注解。