spring对注解的拓展,早已超越J2EE的规约。通过注解可以实现其派生性(Annotation Hierarchy)。自从spring2.5开始,每个大版本都对其进行了增强。
何为派生?
没错一般能想到的就是属性派生,直接上代码,其实Parent和Child看似是派生的关系,但实则并无关系!
它们是两个毫无关联的接口(我在面试的时候会提问:注解和接口的关系),通过javap -v .\Child.class便可得知
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Parent {
String name() default "a";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Parent
public @interface Child {
String name() default "b";
}
@Child
class Home { }
@Test
public void metaTest() {
Annotation[] annotations = Home.class.getDeclaredAnnotations();
System.out.println(Arrays.toString(annotations));//[@com.yh.lucky.day.service.Child(name=Jack)]
annotations = annotations[0].annotationType().getDeclaredAnnotations();
System.out.println(Arrays.toString(annotations));//[@java.lang.annotation.Target(value=[TYPE]), @java.lang.annotation.Retention(value=RUNTIME), @java.lang.annotation.Documented(), @com.yh.lucky.day.service.Parent(name=John)]
}
那派生就不是真正意义上的派生(Override),而spring对其加以拓展,将其界定在层次性:
@Parent @Child
也就是说,有层次结构的注解,spring就认定是具备派生性(extends),并且派生性强调的类型(Child extends Parent)。
Component
在spring中有很多*@Repository,@Service,@Controller,@Configuration等*均派生于@Component,这也就是为什么你添加了一个注解(只需要标记为@Component),而不用改动spring core。
- Spring2.5 仅支持单层次的@Component派生,未采用层次递归获取Annotation[]
- Spring3.x 实现仅两层@Component派生
- Spring4.x开始采用递归方式查找元注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface HignLevelAnnotation {
String value() default "a";
}
@HignLevelAnnotation
public class TestComponent {//此时可以自动注入到spring ioc中
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@HignLevelAnnotation
public @interface MiddleLevelAnnotation {
String value() default "b";
}
@MiddleLevelAnnotation
public class TestComponent {//此时还可以自动注入到spring ioc中
}
@Test
public void metaTest() throws IOException {
CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
//ResourcePatternUtils
Resource resource = new ClassPathResource("TestComponent.class",TestComponent.class);
AnnotationMetadata asmVisitor = readerFactory.getMetadataReader(resource).getAnnotationMetadata();
//AnnotationMetadataReadingVisitor#attributesMap内部存储了注解记录
System.out.println(((AnnotationMetadataReadingVisitor)asmVisitor).isAnnotated("org.springframework.stereotype.Component"));
//上面的Asm可能难懂,那下面反射的更易懂
Component cp = AnnotationUtils.findAnnotation(TestComponent.class, Component.class);
System.out.println(cp.value());
HignLevelAnnotation cp2 = AnnotationUtils.findAnnotation(TestComponent.class, HignLevelAnnotation.class);
System.out.println(cp2.value());
}
原理-AnnotationMetadataReadingVisitor
在之前的章节讲过MetadataReaderFactory,读取类或者注解相关信息有两种方式:反射和ASM。
ClassMetadata,类元信息抽象,StandardClassMetadata(反射),ClassReader(ASM)MethodMetadata,方法元信息抽象,StandardMethodMetadata(反射),MethodMetadataReadingVisitor(ASM)AnnotationMetadata,注解元信息抽象,StandardAnnotationMetadata(反射),AnnotationMetadataReadingVisitor(ASM)AnnotationAttributes,注解属性抽象MetadataReader,元信息读取抽象,通过MetadataReaderFactory获取
而``AnnotationMetadataReadingVisitor的内部实现使用AnnotationAttributesReadingVisitor`类来递归的查找元注解。反射的API类`AnnotationUtils`易用性则更强。
那要满足真正意义上的派生,不仅仅时类型,spring为此开发了@AliasFor。
本文深入探讨了Spring框架中注解的派生性,包括@Component注解的层次结构和派生机制,以及如何利用元注解实现注解的递归查找。介绍了@Parent和@Child注解的示例,展示了Spring如何处理这些层次性的注解。

被折叠的 条评论
为什么被折叠?



