一、Spring元注解
Spring有很多注解类型,有些是元注解,有些是派生注解,比如:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any (or empty String otherwise)
*/
@AliasFor(annotation = Component.class)
String value() default "";
}
@Service
是被@Component
注解的,而@Component
是Spring提供的元注解,因此@Service
也具有将一个类标记为Spring Bean的能力。
二、Spring处理派生注解的方式
首先定义个派生注解,并且应用该注解,方便通过DBUG来分析Spring源代码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface MyConfigurationAnnotation {
}
@MyConfigurationAnnotation
public class MyConfiguration {
}
以@Configuration
为例,该注解会被ConfigurationClassPostProcessor#processConfigBeanDefinitions
方法所解析:
该方法又通过
ConfigurationClassUtils#checkConfigurationClassCandidate
来处理。
查找是否被Configuration所注解.png
metadata
是一个AnnotationMetadata
实例,下面看下AnnotationMetadata
的继承关系:AnnotationMetadata继承关系.png
metadata.getAnnotationAttributes(Configuration.class.getName())
通过层层调用最终会定位到AnnotatedTypeMetadata#getAnnotationAttributes(String annotationName, boolean classValuesAsString)
方法:AnnotatedTypeMetaData.png
到目前为止还是无法了解Spring是如何查找注解的,但是还是看到了一个get
方法,所以只能硬着头皮继续往下找,通过DEBUG发现它调用的是MergedAnnotationsCollection#get
,经过跳转最终在MergedAnnotationsCollection#find
方法中找到了关键代码:
以前面定义的MyConfiguration
为例,它被自定义的@MyConfigurationAnnotation
所注解,mappings
会存储所有的@MyConfigurationAnnotation
注解包括@Configuration
、@Component
、@Indexed
,所有注解的注解都会包括进来。这样当查询@Configuration
注解是否在类MyConfiguration
上定义时就能返回指定的信息,自定义的@MyConfigurationAnnotation
具有了跟@Configuration
一样的能力。
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
到目前为止Spring是如何让派生注解拥有元注解的能力已经了解的差不多了,但是还有一个小疑问就是this.mappings[]
数组是哪里生成的,它是如何将所有的注解收集起来的。很幸运在MergedAnnotationsCollection
构造方法中找到了关键代码行:
forAnnotationType.png
forAnnotationType2.png
Cache.png AnnotationTypeMapping.png
经过来回跳转终于在AnnotationTypeMappings
类中看到了关键代码:
Spring就是这样不断循环查找注解的注解来收集所有的已声明的注解。
至于@MyConfigurationAnnotation
是哪里读取的,可以看下ClassReader
583行以及SimpleAnnotationMetadataReadingVisitor
119行
网友评论