docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之组合注解的处理.md
spring Уһرע⣺ע⡣˵springmvc У@Controller ע÷·ȣ@ResponseBody עͼȾֱչʾнһת json أ @RestController ߵĹܣ÷·ͬʱҲֱչʾн£
@Controller
@ResponseBody
public @interface RestController {
/**
* ע
*/
@AliasFor(annotation = Controller.class)
String value() default "";
}
Կ@RestController ϱע⣺@Controller @ResponseBodyͬʱӵߵĹܡ
һӣspring УڱʶһΪ spring bean ʱõЩע⣺@Component``@Repository``@Service ȣٽһ룬 @Repository``@Service ж @Component
@Component
public @interface Repository {
@AliasFor(annotation = Component.class)
String value() default "";
}
@Component
public @interface Service {
@AliasFor(annotation = Component.class)
String value() default "";
}
Ҳ˵@Repository``@Service @Component Ĺܣ
ʵϣԼдһע⣬
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface MyComponent {
@AliasFor(annotation = Component.class)
String value() default "";
}
Ȼʹã
@MyComponent("beanObj3")
public class BeanObj3 {
...
}
spring Ȼ BeanObj3 ʼΪ spring bean
ô spring һأʵϣspring ڴ @MyComponent ʱжϸעǷ @Component ע⣬ͻȡעãȻ @Component Ĵд
ͬأspring ڴ @RestController ʱǰǴ @Controller ʹ @RestController лȡ @Controller ȻдǰǴ @ResponseBody ʹ @RestController лȡ @ResponseBody Ȼд
ˣעеעҪôȡأ
jdk ṩķ
RestController annotation = BeanObj3.class.getAnnotation(MyComponent.class);
õ annotation ضΪ nullԭ Class#getAnnotation ֻܻȡֱӳֵע⣬BeanObj3 ûֱӳ @Component ģ˵õĽΪ null취ҲҲ뵽ˣǼ¶ȡ "עע"ôʾ£
public class AnnotationHandler {
/**
* jdkṩԪע
*/
private static Set<Class<?>> metaAnnotations = new HashSet<>();
static {
metaAnnotations.add(Target.class);
metaAnnotations.add(Documented.class);
metaAnnotations.add(Retention.class);
}
public static void main(String[] args) {
List<Class<?>> list = getAnnotations(BeanObj3.class);
System.out.println(list);
}
/**
* ȡݹ
*/
public static List<Class<?>> getAnnotations(Class<?> cls) {
// Ÿϵע⣬עע
List<Class<?>> list = new ArrayList<>();
// doGetAnnotations(...) ȡ
doGetAnnotations(list, cls);
return list;
}
/**
* ȡעľ
*/
private static void doGetAnnotations(List<Class<?>> list, Class<?> cls) {
// ȡеע
Annotation[] annotations = cls.getAnnotations();
if(annotations != null && annotations.length > 0) {
for(Annotation annotation : annotations) {
// ȡע
Class<?> annotationType = annotation.annotationType();
// jdkṩԪע
if(metaAnnotations.contains(annotationType)) {
continue;
}
// ݹ
doGetAnnotations(list, annotationType);
}
}
// ע⣬ӵ list
if(cls.isAnnotation()) {
list.add(cls);
}
}
}
Ҫȡ BeanObj3 ע⣬Ϳˣ
// õ BeanObj3 ϵע⣬עע⡱
List<Class<?>> list = AnnotationHandler.getAnnotations(BeanObj3.class);
// ж BeanObj3 עǷ @Component
list.contains(Component.class);
demo DZȽϴֲڣ jdk Ԫע⣬ֻų @Component гֵģ @Component ֮ϵעȡѾ㹻ˣҲҪģûлȡעݡ spring УעⲢֻһǣԶһϵ
// spring bean Ϊ beanObj3
@MyComponent("beanObj3")
public class BeanObj3 {
...
}
AnnotationHandler ܻȡעݣ
spring ôעݵĶȡġ
spring 5.2 УעϢĶȡṩࣺ
AnnotationMetadataReadingVisitorעݵĶȡ࣬ asm ʵ֣ spring5.2 Ѿ @Deprecatedʹ SimpleAnnotationMetadataReadingVisitor˱IJSimpleAnnotationMetadataReadingVisitorעݵĶȡ࣬ asm ʵ֣spring 5.2 ࣬ AnnotationMetadataReadingVisitorҪעǣSimpleAnnotationMetadataReadingVisitor ķʼĬϵģڰ֮ʣͬʱҲ final ģܱ̳УֱӲ spring ṩһࣺSimpleMetadataReaderFactoryͨͿʹ SimpleAnnotationMetadataReadingVisitorStandardAnnotationMetadataעݵĶȡ࣬ڷʵSimpleAnnotationMetadataReadingVisitorspring ûṩֱӲ SimpleAnnotationMetadataReadingVisitor ĻᣬǷװ SimpleMetadataReaderFactory ˣࣺ
ԿSimpleMetadataReaderFactory ҪΪ֣
ֱӿȡĻȡҲ getMetadataReader(...)
getMetadataReader(Resource resource): Resource ȡ getMetadataReader(String className): ȡݣȫ ӴҲתΪ ResourceȻ getMetadataReader(Resource) жȡ
ķֵ MetadataReaderǸɶأǼ¿.
MetadataReaderMetadataReader IJַ£
ԿǸӿڣﷵصľ; SimpleMetadataReader ˣ 3
getResource(): ȡԴgetClassMetadata(): ȡԪgetAnnotationMetadata(): ȡעԪǻȡעϢֻע getAnnotationMetadata()
AnnotationMetadata getAnnotationMetadata();
ص AnnotationMetadataǸɶ
AnnotationMetadataķ
ЩΪࣺ
getXxx(...)עȡӦϢhasXxx(...)жǷijעһ⼸Ĭʵֶ֣ getAnnotations()
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
default Set<String> getAnnotationTypes() {
// getAnnotations()
return getAnnotations().stream()
.filter(MergedAnnotation::isDirectlyPresent)
.map(annotation -> annotation.getType().getName())
.collect(Collectors.toCollection(LinkedHashSet::new));
}
default Set<String> getMetaAnnotationTypes(String annotationName) {
// getAnnotations()
MergedAnnotation<?> annotation = getAnnotations().get(annotationName,
MergedAnnotation::isDirectlyPresent);
if (!annotation.isPresent()) {
return Collections.emptySet();
}
return MergedAnnotations.from(annotation.getType(), SearchStrategy.INHERITED_ANNOTATIONS)
.stream()
.map(mergedAnnotation -> mergedAnnotation.getType().getName())
.collect(Collectors.toCollection(LinkedHashSet::new));
}
default boolean hasAnnotation(String annotationName) {
// getAnnotations()
return getAnnotations().isDirectlyPresent(annotationName);
}
...
}
ٽһ鿴 getAnnotations() AnnotatedTypeMetadata
public interface AnnotatedTypeMetadata {
/**
* ȡע
*/
MergedAnnotations getAnnotations();
...
}
һƺעõռ MergedAnnotations ˣǼ̽
MergedAnnotationsMergedAnnotations IJע£
Provides access to a collection of merged annotations, usually obtained from a source such as a {@link Class} or {@link Method}.
ṩעļϵķʣЩעͨǴ Class Method ֮Դõġ
MergedAnnotations յעļˣļ
// жעǷڣеעж
<A extends Annotation> boolean isPresent(Class<A> annotationType);
// жעǷڣеעжϣķͬǣﴫַ
boolean isPresent(String annotationType);
// жֱעǷڣҲֻжϵǰûиע⣬жעע
<A extends Annotation> boolean isDirectlyPresent(Class<A> annotationType);
// ͬϣﴫַʽΪ"."
boolean isDirectlyPresent(String annotationType);
// ȡע
<A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType);
// ȡע⣬ﴫַʽΪ"."
<A extends Annotation> MergedAnnotation<A> get(String annotationType);
ӷϴ¿ԿMergedAnnotations עļϣṩעжijעǷڣҲԻȡеijע⡣
MergedAnnotationMergedAnnotations עļϣзŵɶأ get(...) ŵ MergedAnnotation MergedAnnotation ֵ֧ķ
ϵķԿMergedAnnotation עݳṩ˷ḻ api ȡעݡ
ʾ
// õ SimpleMetadataReaderFactory ʵյõ SimpleAnnotationMetadataReadingVisitor ȡ
SimpleMetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory();
MetadataReader metadataReader = readerFactory.getMetadataReader(BeanObj3.class.getName());
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// AnnotationMetadata ṩIJصעעص
Set<String> annotationTypes = annotationMetadata.getAnnotationTypes();
System.out.println("-------------");
annotationTypes.forEach(type -> System.out.println(type));
System.out.println("-------------");
// ֱӻȡBeanObj3 ֱӱ @MyComponentģصtrue
boolean exist1 = annotationMetadata.hasAnnotation(MyComponent.class.getName());
System.out.println("hasAnnotation @MyComponent:" + exist1);
// ֱӻȡBeanObj3 ûֱӱ @Componentģصfalse
boolean exist2 = annotationMetadata.hasAnnotation(Component.class.getName());
System.out.println("hasAnnotation @Component:" + exist2);
// ȡ MergedAnnotations
MergedAnnotations annotations = annotationMetadata.getAnnotations();
System.out.println("-------------");
annotations.forEach(annotationMergedAnnotation -> System.out.println(annotationMergedAnnotation));
System.out.println("-------------");
// ֱӻȡBeanObj3 ûֱӱ @Componentģصfalse
boolean directlyPresent = annotations.isDirectlyPresent(Component.class);
System.out.println("directlyPresent Component:" + directlyPresent);
// жûע⣬BeanObj3 ϵ@MyComponentУ @Component ģصtrue
boolean present = annotations.isPresent(Component.class);
System.out.println("present Component:" + present);
// ȡ @Component ע
MergedAnnotation<Component> mergedAnnotation = annotations.get(Component.class);
// @MyComponent value() @AliasFor(annotation = Component.class)
// õ value beanObj3 BeanObj3ôָģ@MyComponent("beanObj3")
String value = mergedAnnotation.getString("value");
System.out.println("Component value:" + value);
// @Component עתΪ AnnotationAttributes
AnnotationAttributes annotationAttributes = mergedAnnotation.asAnnotationAttributes();
System.out.println(annotationAttributes);
У£
-------------
org.springframework.learn.explore.demo01.MyComponent
-------------
hasAnnotation @MyComponent:true
hasAnnotation @Component:false
-------------
@org.springframework.learn.explore.demo01.MyComponent(value=beanObj3)
@org.springframework.stereotype.Component(value=beanObj3)
@org.springframework.stereotype.Indexed()
-------------
directlyPresent Component:false
present Component:true
Component value:beanObj3
{value=beanObj3}
AnnotationAttributes˵ AnnotationAttributes
public class AnnotationAttributes extends LinkedHashMap<String, Object> {
...
}
ʵ LinkedHashMapṩIJַ£
ﲻѿAnnotationAttributes ǰעֵ mapkey Ϊvalue Ϊֵ
StandardAnnotationMetadataǽ StandardAnnotationMetadata:
public class StandardAnnotationMetadata extends StandardClassMetadata
implements AnnotationMetadata {
/**
* Create a new {@code StandardAnnotationMetadata} wrapper for the given Class.
* @param introspectedClass the Class to introspect
* @see #StandardAnnotationMetadata(Class, boolean)
* @deprecated since 5.2 in favor of the factory method
* {@link AnnotationMetadata#introspect(Class)}
*/
@Deprecated
public StandardAnnotationMetadata(Class<?> introspectedClass) {
this(introspectedClass, false);
}
...
}
StandardAnnotationMetadata ʵ AnnotationMetadata ӿڣעIJܵ AnnotationMetadata ̫Ͳˡ
StandardAnnotationMetadata Ĺ췽Ѿˣʹ AnnotationMetadata#introspect(Class) ȡ StandardAnnotationMetadata ʵǣǿ
// ȡ annotationMetadata ʵ StandardAnnotationMetadata
AnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(BeanObj3.class);
//----------- SimpleAnnotationMetadataReadingVisitor һģһ
// AnnotationMetadata ṩIJصעעص
Set<String> annotationTypes = annotationMetadata.getAnnotationTypes();
System.out.println("-------------");
annotationTypes.forEach(type -> System.out.println(type));
System.out.println("-------------");
// ֱӻȡBeanObj3 ֱӱ @MyComponentģصtrue
boolean exist1 = annotationMetadata.hasAnnotation(MyComponent.class.getName());
System.out.println("hasAnnotation @MyComponent:" + exist1);
// ֱӻȡBeanObj3 ûֱӱ @Componentģصfalse
boolean exist2 = annotationMetadata.hasAnnotation(Component.class.getName());
System.out.println("hasAnnotation @Component:" + exist2);
// ȡ MergedAnnotations
MergedAnnotations annotations = annotationMetadata.getAnnotations();
System.out.println("-------------");
annotations.forEach(annotationMergedAnnotation -> System.out.println(annotationMergedAnnotation));
System.out.println("-------------");
// ֱӻȡBeanObj3 ûֱӱ @Componentģصfalse
boolean directlyPresent = annotations.isDirectlyPresent(Component.class);
System.out.println("directlyPresent Component:" + directlyPresent);
// жûע⣬BeanObj3 ϵ@MyComponentУ @Component ģصtrue
boolean present = annotations.isPresent(Component.class);
System.out.println("present Component:" + present);
// ȡ @Component ע
MergedAnnotation<Component> mergedAnnotation = annotations.get(Component.class);
// @MyComponent value() @AliasFor(annotation = Component.class)
// õ value beanObj3 BeanObj3ôָģ@MyComponent("beanObj3")
String value = mergedAnnotation.getString("value");
System.out.println("Component value:" + value);
// @Component עתΪ AnnotationAttributes
AnnotationAttributes annotationAttributes = mergedAnnotation.asAnnotationAttributes();
System.out.println(annotationAttributes);
н£
-------------
org.springframework.learn.explore.demo01.MyComponent
-------------
hasAnnotation @MyComponent:true
hasAnnotation @Component:false
-------------
@org.springframework.learn.explore.demo01.MyComponent(value=beanObj3)
@org.springframework.stereotype.Component(value=beanObj3)
@org.springframework.stereotype.Indexed()
-------------
directlyPresent Component:false
present Component:true
Component value:beanObj3
{value=beanObj3}
ʾǧ࣬յõ MergedAnnotationsȻͨжעǷڡȡעֵ
SimpleAnnotationMetadataReadingVisitor StandardAnnotationMetadata ҪڣSimpleAnnotationMetadataReadingVisitor ǻ asm ʵ֣StandardAnnotationMetadata ǻڷʵ֣ʹʱӦҪôѡأ
ڻڷҪȼص jvm еģҵжǣǰûмص jvm Уʹ SimpleAnnotationMetadataReadingVisitorѾص jvm ˣ߽Կʹ
ʵϣ spring ɨΣȡϵעʱʹõĶ SimpleAnnotationMetadataReadingVisitorΪʱಢûмص jvmʹ StandardAnnotationMetadata ȡͻᵼǰءǰʲôأjava ǰصģе jvm ڶûõȫˣͰװ˷ڴˡ
ǰʾУȡעģ
// ȡ annotationMetadataҲʹ SimpleMetadataReaderFactory ȡ
AnnotationMetadata annotationMetadata = AnnotationMetadata.introspect(BeanObj3.class);
MergedAnnotations annotations = annotationMetadata.getAnnotations();
// жעǷ
boolean present = annotations.isPresent(Component.class);
// ȡע
MergedAnnotation<Component> mergedAnnotation = annotations.get(Component.class);
AnnotationAttributes annotationAttributes = mergedAnnotation.asAnnotationAttributes();
˵ȡעԲȽ϶࣬㣬뵽ԽЩװһндspring Ҳôģ͵ý spring עصࣺAnnotationUtils AnnotatedElementUtils``AnnotationUtils ֱӻȡעֵᴦԸǣ AnnotatedElementUtils ᴦԸǡ
ʲôԸأ
˵@MyComponent
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
// עComponentֵָ123
@Component("123")
public @interface MyComponent {
@AliasFor(annotation = Component.class)
String value() default "";
}
@MyComponent עУָ @Component value ֵΪ 123Ȼôָ @MyComponent value ֵ
@MyComponent("beanObj3")
public class BeanObj3 {
...
}
spring ʼõ BeanObj3 123 beanObj3 أ @MyComponent value Ϊ beanObj3 ˵Ȼϣ bean Ϊ beanObj3 spring ҲôģԸˣ@MyComponent value @Component value ֵ
AnnotationUtils/AnnotatedElementUtils ܵ SimpleAnnotationMetadataReadingVisitor/StandardAnnotationMetadata Ǻιϵأ
ʹ SimpleAnnotationMetadataReadingVisitor/StandardAnnotationMetadata ʱҪõ MergedAnnotations ٽһϵвжעǷڡȡעֵȣ AnnotationUtils/AnnotatedElementUtils Դ룬ͻᷢǵطҲDz MergedAnnotations ࣬ȡע⣺
AnnotationUtils#getAnnotation(AnnotatedElement, Class<A>)
public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement,
Class<A> annotationType) {
if (AnnotationFilter.PLAIN.matches(annotationType) ||
AnnotationsScanner.hasPlainJavaAnnotationsOnly(annotatedElement)) {
return annotatedElement.getAnnotation(annotationType);
}
// ͨ MergedAnnotations лȡ
return MergedAnnotations.from(annotatedElement,
SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none())
.get(annotationType).withNonMergedAttributes()
.synthesize(AnnotationUtils::isSingleLevelPresent).orElse(null);
}
AnnotatedElementUtils#getAllMergedAnnotations(AnnotatedElement, Class<A>)
public static <A extends Annotation> Set<A> getAllMergedAnnotations(
AnnotatedElement element, Class<A> annotationType) {
return getAnnotations(element).stream(annotationType)
.collect(MergedAnnotationCollectors.toAnnotationSet());
}
// AnnotatedElementUtils#getAnnotations ҲDz MergedAnnotations ķ
private static MergedAnnotations getAnnotations(AnnotatedElement element) {
return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS,
RepeatableContainers.none());
}
ˣAnnotationUtils/AnnotatedElementUtils SimpleAnnotationMetadataReadingVisitor/StandardAnnotationMetadata ײ㶼Dz MergedAnnotations ġ
AnnotationUtilsAnnotationUtils ֵ֧IJַ£
ʵʹЩ
// BeanObj3 ȡ @Component
Annotation annotation = AnnotationUtils.getAnnotation(BeanObj3.class, Component.class);
if(null == annotation) {
System.out.println("עⲻڣ");
return;
}
System.out.println("annotation: " + annotation);
// ȡ AnnotationAttributes
AnnotationAttributes annotationAttributes
= AnnotationUtils.getAnnotationAttributes(BeanObj3.class, annotation);
System.out.println("AnnotationAttributes: " + annotationAttributes);
// ȡ annotationAttributeMap
Map<String, Object> annotationAttributeMap = AnnotationUtils.getAnnotationAttributes(annotation);
System.out.println("annotationAttributeMap: " + annotationAttributeMap);
// ȡvalueֵ
Object value = AnnotationUtils.getValue(annotation, "value");
System.out.println("value: " + value);
£
annotation: @org.springframework.stereotype.Component(value=123)
AnnotationAttributes: {value=123}
annotationAttributeMap: {value=123}
value: 123
ӽֱͨ AnnotationUtils.getAnnotation(...) Ҳܻȡ @Component עģ BeanObj3 ûֱӱ @Component. Ҫעǣȡ @Component value ֵ "123" @MyComponent õ beanObj3Ҳ֤ AnnotationUtils ȡֵʱԸDz
AnnotatedElementUtilsAnnotatedElementUtils ֵ֧IJַ£
ʾɣ
// 1\. жǷ Component ע
boolean result = AnnotatedElementUtils.hasAnnotation(BeanObj3.class, Component.class);
System.out.println("hasAnnotation: " + result);
// 2\. ȡ attributeMapԿǣȡ @Component @MyComponent õĽһ
// Component attributeMap: {value=[123]}
MultiValueMap<String, Object> attributeMap1 = AnnotatedElementUtils
.getAllAnnotationAttributes(BeanObj3.class, Component.class.getName());
System.out.println("Component attributeMap: " + attributeMap1);
// MyComponent attributeMap: {value=[beanObj3]}
MultiValueMap<String, Object> attributeMap2 = AnnotatedElementUtils
.getAllAnnotationAttributes(BeanObj3.class, MyComponent.class.getName());
System.out.println("MyComponent attributeMap: " + attributeMap2);
// 3\. ȡе @Component ע⣬value=beanObj3
Set<Component> mergedAnnotations = AnnotatedElementUtils
.getAllMergedAnnotations(BeanObj3.class, Component.class);
System.out.println("mergedAnnotations: " + mergedAnnotations);
// 4\. ȡֵ{value=beanObj3}
AnnotationAttributes attributes = AnnotatedElementUtils
.getMergedAnnotationAttributes(BeanObj3.class, Component.class);
System.out.println("attributes: " + attributes);
// 5\. ȡ MyComponent ϵע
Set<String> types = AnnotatedElementUtils
.getMetaAnnotationTypes(BeanObj3.class, MyComponent.class);
System.out.println("types: " + types);
£
hasAnnotation: true
Component attributeMap: {value=[123]}
MyComponent attributeMap: {value=[beanObj3]}
mergedAnnotations: [@org.springframework.stereotype.Component(value=beanObj3)]
attributes: {value=beanObj3}
types: [org.springframework.stereotype.Component, org.springframework.stereotype.Indexed]
Ӵڵõ Set<Component> AnnotationAttributes УֵѾϲ.
ѡʹ AnnotationUtils AnnotatedElementUtils ʱԸҪҪԸѡҪԸǣʹ AnnotatedElementUtilsҪʹ AnnotationUtils ɣ
Ľ spring עIJҪ SimpleAnnotationMetadataReadingVisitor StandardAnnotationMetadata ʹ÷ʹȽ϶ֽ࣬ spring ṩࣺAnnotationUtils AnnotatedElementUtilsҪԸǣҪʹ AnnotatedElementUtilsҪʹ AnnotationUtils
ԭӣhttps://my.oschina.net/funcy/blog/4633161 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע