【小家Spring】Spring贡献的多个注解相关的工具类:AnnotationUtils、AnnotatedElementUtils、AnnotationConfigUtils...(中)

简介: 【小家Spring】Spring贡献的多个注解相关的工具类:AnnotationUtils、AnnotatedElementUtils、AnnotationConfigUtils...(中)
  • public static boolean isInJavaLangAnnotationPackage(@Nullable Annotation annotation):是否是JDK的注解(String的重载方法,省略)


    public static void main(String[] args) {
        MyAnno myAnno = Eat.class.getAnnotation(MyAnno.class);
        Target target = MyAnno.class.getAnnotation(Target.class);
        System.out.println(AnnotationUtils.isInJavaLangAnnotationPackage(myAnno)); //false
        System.out.println(AnnotationUtils.isInJavaLangAnnotationPackage(target)); //true
    }


  • public static Map<String, Object> getAnnotationAttributes(Annotation annotation):获取这个注解的所有属性值们,用map保存(非常重要)
  • public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap):最全的一个方法 classValuesAsString:true表示把Class类型的都转换为String类型,nestedAnnotationsAsMap:true表示连内嵌的注解也解析出来(默认都是false的) 注意此处返回的是AnnotationAttributes,它其实就是个Map,提供了各种更便捷的获取方法:getString、getBoolean等等
  • public static AnnotationAttributes getAnnotationAttributes(@Nullable AnnotatedElement annotatedElement, Annotation annotation):annotatedElement表示被标注了后面这个注解的元素,如果不知道,你就传null吧

// 给注解增加属性、有Class属性  也有嵌套属性
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping
@Inherited
@interface MyAnno {
    String value() default "this is mine";
    Class<? extends Number> clazz() default Integer.class;
    // 注解类型的属性
    Component anno() default @Component;
}
    public static void main(String[] args) {
        MyAnno myAnno = Eat.class.getAnnotation(MyAnno.class);
        // 它原理是调用了下面的底层方法  传值为两个false
        Map<String, Object> myAnnoAttrs = AnnotationUtils.getAnnotationAttributes(myAnno);
        // 此处可以看到clazz输出的是class类型,并不是字符串。anno也是调用了toString方法,并没有解析内嵌的
        System.out.println(myAnnoAttrs); //{clazz=class java.lang.Integer, value=this is mine, anno=@org.springframework.stereotype.Component(value=mytest)}
        // =====传双true
        AnnotationAttributes annotationAttributes = AnnotationUtils.getAnnotationAttributes(myAnno, true, true);
        System.out.println(annotationAttributes); //{clazz=java.lang.Integer, value=this is mine, anno={value=mytest}}
        // 经过我测试,第一个参数写Object.class都无所谓 结果和上面一样的
        // 若哪位小伙伴知道这个参数有不同的解释,请告知哈
        AnnotationAttributes classAnno = AnnotationUtils.getAnnotationAttributes(Object.class, myAnno, true, true);
        System.out.println(classAnno);
    }


  • public static Object getValue(Annotation annotation):获取注解内指定属性的值
    public static void main(String[] args) {
        MyAnno myAnno = Eat.class.getAnnotation(MyAnno.class);
        // 个人觉得还不如直接:myAnno.value()呢  哈哈(Spring底层用的Method做的)
        System.out.println(AnnotationUtils.getValue(myAnno)); //this is mine
        System.out.println(AnnotationUtils.getValue(myAnno, "clazz")); //class java.lang.Integer
        System.out.println(AnnotationUtils.getValue(myAnno, "aaa")); //null
    }
  • public static Object getDefaultValue(@Nullable Annotation annotation, @Nullable String attributeName):和上面相比,这里只拿默认值。若没有设置默认值,那就返回null
  • public static <A extends Annotation> A synthesizeAnnotation(A annotation, @Nullable AnnotatedElement annotatedElement):提供出一个public的方法,外部也能调用代理指定的注解了(各种重载方法略)
  • public static void clearCache():我们也可以手动调用此方法,清除内部的缓存

顺便提一句,其内部有一个私有的静态内部类private static class AliasDescriptor:专程用来处理@AliasFor注解


AnnotatedElementUtils:在AnnotatedElement finding annotations, meta-annotations, and repeatable annotations(@since 4.0)

  • public static AnnotatedElement forAnnotations(final Annotation... annotations):给这么多的Annos提供一个适配器(内部就是new了一个AnnotatedElement匿名内部类,没啥特殊的)
  • public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, String annotationName):简单的说,就是返回指定Class上面这个注解上的注解(若没有,返回null) 备注:不包含Java的元注解哦~
  • public static boolean hasMetaAnnotationTypes(AnnotatedElement element, Class<? extends Annotation> annotationType):
  • public static boolean isAnnotated(AnnotatedElement element, Class<? extends Annotation> annotationType):厉害。不管是注解,还是有注解的注解标注了 都返回true

    public static void main(String[] args) {
        Set<String> metaAnnotationTypes = AnnotatedElementUtils.getMetaAnnotationTypes(Child.class, MyAnno.class);
        System.out.println(metaAnnotationTypes); //[org.springframework.web.bind.annotation.RequestMapping, org.springframework.web.bind.annotation.Mapping]
        // 请注意此处:因为是元注解types,所以第一个是false,第二个是true
        System.out.println(AnnotatedElementUtils.hasMetaAnnotationTypes(Child.class, MyAnno.class)); // false
        System.out.println(AnnotatedElementUtils.hasMetaAnnotationTypes(Child.class, RequestMapping.class)); // true
        // 注意此处  两个都是true哦~~~
        System.out.println(AnnotatedElementUtils.isAnnotated(Child.class, MyAnno.class)); // true
        System.out.println(AnnotatedElementUtils.isAnnotated(Child.class, RequestMapping.class)); //true
    }


  • 关于getMerge之类的方法,在后面讲@AliasFor的时候再详说吧


AnnotationBeanUtils:拷贝注解值到指定的Bean中



它在org.springframework.beans.annotation包下,并且这个包下只有它一个类。该类只有一个核心方法。


public abstract class AnnotationBeanUtils {
  // excludedProperties 排除的属性值不拷贝
  public static void copyPropertiesToBean(Annotation ann, Object bean, String... excludedProperties) {
    copyPropertiesToBean(ann, bean, null, excludedProperties);
  }
  public static void copyPropertiesToBean(Annotation ann, Object bean, @Nullable StringValueResolver valueResolver, String... excludedProperties) {
    // 用set去重
    Set<String> excluded = new HashSet<>(Arrays.asList(excludedProperties));
    // 这是拿到该注解的所有属性(编译后都是通过method的方式存储的)
    Method[] annotationProperties = ann.annotationType().getDeclaredMethods();
    // 吧这个Bean包装成一个BeanWrapper 
    BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(bean);
    for (Method annotationProperty : annotationProperties) {
      String propertyName = annotationProperty.getName();
      if (!excluded.contains(propertyName) && bw.isWritableProperty(propertyName)) {
        // 拿到注解的值
        Object value = ReflectionUtils.invokeMethod(annotationProperty, ann);
        // 若是字符串类型,还可以处理(也就值支持到了{}这种占位符形式)
        if (valueResolver != null && value instanceof String) {
          value = valueResolver.resolveStringValue((String) value);
        }
        // 把该Value值设置进去
        bw.setPropertyValue(propertyName, value);
      }
    }
  }
}


备注:这个我们一般用不着,Spring内在JMX相关类中使用。比如AnnotationJmxAttributeSource

AnnotationConfigUtils:(重要),和Config配置类有关的注解工具类


AnnotationConfigUtils是一个Spring内部工具类,用于识别注解配置类中的bean定义。(和Bean注册有关)


public class AnnotationConfigUtils {
  // 这个常量在我们AnnotationConfigApplicationContext#setBeanNameGenerator的时候会执行这么一句话:
  //getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator)
  //  然后在处理@Configuration里的@Bean的时候,会get出来处理名字
  public static final String CONFIGURATION_BEAN_NAME_GENERATOR =
      "org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
  //============= Spring默认会注册进去的7个Bean(若没导包,有可能是5个哦) ===========================
  public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
      "org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
  public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
      "org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
  public static final String REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
      "org.springframework.context.annotation.internalRequiredAnnotationProcessor";
  public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
      "org.springframework.context.annotation.internalCommonAnnotationProcessor";
  public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME =
      "org.springframework.context.annotation.internalPersistenceAnnotationProcessor";
  public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
      "org.springframework.context.event.internalEventListenerProcessor";
  public static final String EVENT_LISTENER_FACTORY_BEAN_NAME =
      "org.springframework.context.event.internalEventListenerFactory";
  private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME =
      "org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";
  private static final boolean jsr250Present =
      ClassUtils.isPresent("javax.annotation.Resource", AnnotationConfigUtils.class.getClassLoader());
  private static final boolean jpaPresent =
      ClassUtils.isPresent("javax.persistence.EntityManagerFactory", AnnotationConfigUtils.class.getClassLoader()) &&
      ClassUtils.isPresent(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, AnnotationConfigUtils.class.getClassLoader());
}


  • public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source):该方法主要是向容器注册了一组基础设施PostProcessor bean定义,这些bean定义生成的PostProcessor实例被框架自己用于识别注解配置类中的bean定义(就是我们上面说的7大默认Bean定义,role均为:BeanDefinition.ROLE_INFRASTRUCTURE表示框架自己用的)。 它还为Bean工厂设置了:setDependencyComparator和setAutowireCandidateResolver
  • public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd):处理通用的Bean定义上的注解,该方法从原始bean定义的元数据中获取那些通用的注解信息:@Lazy,@DependsOn,@Role,@Description,然后设置AnnotatedBeanDefinition实例相应的属性


基本上这个工具类是Spring内部使用的,我们用不着。它在org.springframework.context.annotation包内

ConfigurationClassUtils:Spring内部处理@Configuration的工具类

这个工具类只处理@Configuration配置类的。是Full模式还是Lite模式

  public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
    return metadata.isAnnotated(Configuration.class.getName());
  }
  public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata){
  //有@Component、@Component、@Import、@ImportResource标注的
  // 或者类内部有@Bean标注的方法  都属于Lite模式的配置类
  ...
  }
  public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
    return (isFullConfigurationCandidate(metadata) || isLiteConfigurationCandidate(metadata));
  }
  /
  public static boolean isFullConfigurationClass(BeanDefinition beanDef) {
    return CONFIGURATION_CLASS_FULL.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
  }
  public static boolean isLiteConfigurationClass(BeanDefinition beanDef) {
    return CONFIGURATION_CLASS_LITE.equals(beanDef.getAttribute(CONFIGURATION_CLASS_ATTRIBUTE));
  }
  // 获取@Order的值 since Spring5.0
  @Nullable
  public static Integer getOrder(AnnotationMetadata metadata) {
    Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
    return (orderAttributes != null ? ((Integer) orderAttributes.get(AnnotationUtils.VALUE)) : null);
  }
  // since Spring4.2
  public static int getOrder(BeanDefinition beanDef) {
    Integer order = (Integer) beanDef.getAttribute(ORDER_ATTRIBUTE);
    return (order != null ? order : Ordered.LOWEST_PRECEDENCE);
  }


OrderUtils:处理@Order和javax.annotation.Priority


public abstract class OrderUtils {
  @Nullable
  public static Integer getOrder(Class<?> type) {
    Order order = AnnotationUtils.findAnnotation(type, Order.class);
    if (order != null) {
      return order.value();
    }
    // 兼容到了JDK6提供的javax.annotation.Priority这个注解(需要额外导包)
    Integer priorityOrder = getPriority(type);
    if (priorityOrder != null) {
      return priorityOrder;
    }
    return null;
  }
  @Nullable
  public static Integer getPriority(Class<?> type) {
    if (priorityAnnotationType != null) {
      Annotation priority = AnnotationUtils.findAnnotation(type, priorityAnnotationType);
      if (priority != null) {
        return (Integer) AnnotationUtils.getValue(priority);
      }
    }
    return null;
  }
// 最常调用的还是下列方法:
  public static int getOrder(Class<?> type, int defaultOrder) {
    Integer order = getOrder(type);
    return (order != null ? order : defaultOrder);
  }
  @Nullable
  public static Integer getOrder(Class<?> type, @Nullable Integer defaultOrder) {
    Integer order = getOrder(type);
    return (order != null ? order : defaultOrder);
  }
}



相关文章
|
2月前
|
Java 开发者 Spring
【SpringBoot 异步魔法】@Async 注解:揭秘 SpringBoot 中异步方法的终极奥秘!
【8月更文挑战第25天】异步编程对于提升软件应用的性能至关重要,尤其是在高并发环境下。Spring Boot 通过 `@Async` 注解简化了异步方法的实现。本文详细介绍了 `@Async` 的基本用法及配置步骤,并提供了示例代码展示如何在 Spring Boot 项目中创建与管理异步任务,包括自定义线程池、使用 `CompletableFuture` 处理结果及异常情况,帮助开发者更好地理解和运用这一关键特性。
125 1
|
2月前
|
XML Java 测试技术
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
这篇文章介绍了Spring5框架的三个新特性:支持@Nullable注解以明确方法返回、参数和属性值可以为空;引入函数式风格的GenericApplicationContext进行对象注册和管理;以及如何整合JUnit5进行单元测试,同时讨论了JUnit4与JUnit5的整合方法,并提出了关于配置文件加载的疑问。
Spring5入门到实战------17、Spring5新功能 --Nullable注解和函数式注册对象。整合JUnit5单元测试框架
|
2月前
|
缓存 Java 数据库连接
Spring Boot奇迹时刻:@PostConstruct注解如何成为应用初始化的关键先生?
【8月更文挑战第29天】作为一名Java开发工程师,我一直对Spring Boot的便捷性和灵活性着迷。本文将深入探讨@PostConstruct注解在Spring Boot中的应用场景,展示其在资源加载、数据初始化及第三方库初始化等方面的作用。
53 0
|
7天前
|
Java Spring 容器
Spring使用异步注解@Async正确姿势
Spring使用异步注解@Async正确姿势,异步任务,spring boot
|
7天前
|
XML Java 数据格式
spring复习03,注解配置管理bean
Spring框架中使用注解配置管理bean的方法,包括常用注解的标识组件、扫描组件、基于注解的自动装配以及使用注解后的注意事项,并提供了一个基于注解自动装配的完整示例。
spring复习03,注解配置管理bean
|
7天前
|
XML 前端开发 Java
控制spring框架注解介绍
控制spring框架注解介绍
|
20天前
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
|
2月前
|
Java 数据安全/隐私保护 Spring
揭秘Spring Boot自定义注解的魔法:三个实用场景让你的代码更加优雅高效
揭秘Spring Boot自定义注解的魔法:三个实用场景让你的代码更加优雅高效
|
2月前
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
2月前
|
监控 安全 Java
【开发者必备】Spring Boot中自定义注解与处理器的神奇魔力:一键解锁代码新高度!
【8月更文挑战第29天】本文介绍如何在Spring Boot中利用自定义注解与处理器增强应用功能。通过定义如`@CustomProcessor`注解并结合`BeanPostProcessor`实现特定逻辑处理,如业务逻辑封装、配置管理及元数据分析等,从而提升代码整洁度与可维护性。文章详细展示了从注解定义、处理器编写到实际应用的具体步骤,并提供了实战案例,帮助开发者更好地理解和运用这一强大特性,以实现代码的高效组织与优化。
56 0
下一篇
无影云桌面