小言_互联网的博客

spring core:@Component的派生性

244人阅读  评论(0)

spring对注解的拓展,早已超越J2EE的规约。通过注解可以实现其派生性(Annotation Hierarchy)。自从spring2.5开始,每个大版本都对其进行了增强。

何为派生?

没错一般能想到的就是属性派生,直接上代码,其实ParentChild看似是派生的关系,但实则并无关系!

它们是两个毫无关联的接口(我在面试的时候会提问:注解和接口的关系),通过javap -v .\Child.class便可得知


  
  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface Parent {
  5. String name() default "a";
  6. }
  7. @Target(ElementType.TYPE)
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Documented
  10. @Parent
  11. public @interface Child {
  12. String name() default "b";
  13. }
  14. @Child
  15. class Home { }
  16. @Test
  17. public void metaTest() {
  18. Annotation[] annotations = Home.class.getDeclaredAnnotations();
  19. System.out.println(Arrays.toString(annotations)); //[@com.yh.lucky.day.service.Child(name=Jack)]
  20. annotations = annotations[ 0].annotationType().getDeclaredAnnotations();
  21. 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)]
  22. }

那派生就不是真正意义上的派生(Override),而spring对其加以拓展,将其界定在层次性:


   
  1. @Parent
  2. @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开始采用递归方式查找元注解

  
  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Component
  5. public @interface HignLevelAnnotation {
  6. String value() default "a";
  7. }
  8. @HignLevelAnnotation
  9. public class TestComponent { //此时可以自动注入到spring ioc中
  10. }
  11. @Target(ElementType.TYPE)
  12. @Retention(RetentionPolicy.RUNTIME)
  13. @Documented
  14. @HignLevelAnnotation
  15. public @interface MiddleLevelAnnotation {
  16. String value() default "b";
  17. }
  18. @MiddleLevelAnnotation
  19. public class TestComponent { //此时还可以自动注入到spring ioc中
  20. }
  21. @Test
  22. public void metaTest() throws IOException {
  23. CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
  24. //ResourcePatternUtils
  25. Resource resource = new ClassPathResource( "TestComponent.class",TestComponent.class);
  26. AnnotationMetadata asmVisitor = readerFactory.getMetadataReader(resource).getAnnotationMetadata();
  27. //AnnotationMetadataReadingVisitor#attributesMap内部存储了注解记录
  28. System.out.println(((AnnotationMetadataReadingVisitor)asmVisitor).isAnnotated( "org.springframework.stereotype.Component"));
  29. //上面的Asm可能难懂,那下面反射的更易懂
  30. Component cp = AnnotationUtils.findAnnotation(TestComponent.class, Component.class);
  31. System.out.println(cp.value());
  32. HignLevelAnnotation cp2 = AnnotationUtils.findAnnotation(TestComponent.class, HignLevelAnnotation.class);
  33. System.out.println(cp2.value());
  34. }

原理-AnnotationMetadataReadingVisitor

之前的章节讲过MetadataReaderFactory,读取类或者注解相关信息有两种方式:反射和ASM。

  • ClassMetadata,类元信息抽象,StandardClassMetadata(反射),ClassReader(ASM)
  • MethodMetadata,方法元信息抽象,StandardMethodMetadata(反射),MethodMetadataReadingVisitor(ASM)
  • AnnotationMetadata,注解元信息抽象,StandardAnnotationMetadata(反射),AnnotationMetadataReadingVisitor(ASM)
  • AnnotationAttributes,注解属性抽象
  • MetadataReader,元信息读取抽象,通过MetadataReaderFactory获取

而``AnnotationMetadataReadingVisitor的内部实现使用AnnotationAttributesReadingVisitor`类来递归的查找元注解。反射的API类`AnnotationUtils`易用性则更强。

那要满足真正意义上的派生,不仅仅时类型,spring为此开发了@AliasFor


转载:https://blog.csdn.net/itsoftchenfei/article/details/103783052
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场