Back to Javatutorial

Spring探秘之组合注解的处理

docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之组合注解的处理.md

1.0.020.9 KB
Original Source

1. ʲôע⣿

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 Ȼд

2. ݹȡָע

ˣעеעҪôȡأ

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 ôעݵĶȡġ

3. spring ȡעϢ

spring 5.2 УעϢĶȡṩࣺ

  • AnnotationMetadataReadingVisitorעݵĶȡ࣬ asm ʵ֣ spring5.2 Ѿ @Deprecatedʹ SimpleAnnotationMetadataReadingVisitor˱IJ
  • SimpleAnnotationMetadataReadingVisitorעݵĶȡ࣬ asm ʵ֣spring 5.2 ࣬ AnnotationMetadataReadingVisitorҪעǣSimpleAnnotationMetadataReadingVisitor ķʼĬϵģ޷ڰ֮ʣͬʱҲ final ģܱ̳У޷ֱӲ spring ṩһࣺSimpleMetadataReaderFactoryͨͿʹ SimpleAnnotationMetadataReadingVisitor
  • StandardAnnotationMetadataעݵĶȡ࣬ڷʵ

3.1 SimpleAnnotationMetadataReadingVisitor

spring ûṩֱӲ SimpleAnnotationMetadataReadingVisitor ĻᣬǷװ SimpleMetadataReaderFactory ˣࣺ

ԿSimpleMetadataReaderFactory ҪΪ֣

  1. ԴĻȡ

ֱӿȡĻȡҲ getMetadataReader(...)

getMetadataReader(Resource resource): Resource ȡ getMetadataReader(String className): ȡݣȫ޶ ӴҲתΪ ResourceȻ getMetadataReader(Resource) жȡ

ķֵ MetadataReaderǸɶأǼ¿.

MetadataReader

MetadataReader 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 ˣǼ̽

MergedAnnotations

MergedAnnotations 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ע⡣

MergedAnnotation

MergedAnnotations עļϣзŵɶأ 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 Ϊֵ

3.2 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ȻͨжעǷڡȡעֵ

3.3 ߵʹó

SimpleAnnotationMetadataReadingVisitor StandardAnnotationMetadata ҪڣSimpleAnnotationMetadataReadingVisitor ǻ asm ʵ֣StandardAnnotationMetadata ǻڷʵ֣ʹʱӦҪôѡأ

ڻڷҪȼص jvm еģҵжǣǰûмص jvm Уʹ SimpleAnnotationMetadataReadingVisitorѾص jvm ˣ߽Կʹ

ʵϣ spring ɨ׶ΣȡϵעʱʹõĶ SimpleAnnotationMetadataReadingVisitorΪʱಢûмص jvmʹ StandardAnnotationMetadata ȡͻᵼǰءǰʲôأjava ǰصģе jvm ڶûõȫˣͰװ˷ڴˡ

4. spring ṩע⹤

ǰʾУȡעģ

// ȡ 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 ġ

4.1 AnnotationUtils

AnnotationUtils ֵ֧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

4.2 AnnotatedElementUtils

AnnotatedElementUtils ֵ֧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 ɣ

5. ܽ

Ľ spring עIJҪ SimpleAnnotationMetadataReadingVisitor StandardAnnotationMetadata ʹ÷ʹȽ϶ֽ࣬ spring ṩࣺAnnotationUtils AnnotatedElementUtilsҪԸǣҪʹ AnnotatedElementUtilsҪʹ AnnotationUtils


ԭӣhttps://my.oschina.net/funcy/blog/4633161 ߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע