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
。
转载:https://blog.csdn.net/itsoftchenfei/article/details/103783052