Stereotype Annotations
本文为读书笔记,如需深入了解,请深入文末参考
以及其派生类是如何被扫描加载的?
spring3.0之前:
- 配置spring <component-scan basePackage: /> xml 中这一配置的处理原理:
比如:
@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Repository { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any */ String value() default "";}
basePackage: ->ContextNameSpaceHandler-> ComponentScanBeanBeanDefinitionParser ->MetadataReader(存储类的信息,包括注解信息) -> ClassPathScanningCandidateComponentProvider ->Typefilter(决定是否加载成Spring Bean)
因为 注解的信息也会被MetadataReader读取到,所以包含@Conponent的类也会被加载。
// 默认filterprotected void registerDefaultFilters() { this.includeFilters.add(new AnnotationTypeFilter(Component.class)); // .....}
知道原理之后,spring提供了可扩展,支持增加Typefilter,这样就不需要依赖spring的 注解了。
Dubbo 2.5.8 @Service的实现也是如此,请参考: ServiceAnnotationBeanPostProcessor.
多层次派生的问题
@Repository--@MyANNOTATION----@Component
两层以上能支持吗,怎么支持?
关键class AnnotationAttributesReadingVisitor. 结论:spring2 支持1层,spring3,支持两层,spring4支持多层。
组合 Annotations
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {}
什么样的注解可以作为 meta-annotation
下面以spring @Cacheable为例子: @Cacheable
<p>This annotation may be used as a <em>meta-annotation</em> to create custom
<em>composed annotations</em> with attribute overrides.
@Cacheable是通过AOP的方式工作的,那么, AOP又是怎么找到我们的SlowService的呢:
@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})@Cacheable(cacheNames="books", key="#isbn")public @interface SlowService {}
看源码:
-
cache pointcut:
CacheOperationSourcePointcut
-> CacheOperationSource -> AnnotatedElementUtils(支持解析 组合annotation) -
cahce advice:
AbstractBeanFactoryPointcutAdvisor
-
proxy bean:
CacheProxyFactoryBean
另外再额外问题,CacheProxyFactoryBean什么时候加载?
所以是否支持组合注解,由该注解的处理类决定。
我们猜测spring会解析classpath下所有的注解,才能为其创建代理类。
使用 spring @AliasFor
@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})@Documentedpublic @interface AliasFor { @AliasFor("attribute") String value() default ""; @AliasFor("value") String attribute() default ""; Class annotation() default Annotation.class;}
在组合注解中会有属性覆盖的问题,如果属性同名的话,覆盖规则是怎么样的?如何显示覆盖? 首先,注解解析完之后,注解的属性会存储在, AnnotationAttributes
中
LinkedHashMap subclass representing annotation attribute key-value pairs as read by AnnotationUtils, AnnotatedElementUtils, and Spring's reflection- and ASM-based AnnotationMetadata implementations. Provides 'pseudo-reification' to avoid noisy Map generics in the calling code as well as convenience methods for looking up annotation attributes in a type-safe fashion.
- 默认同名属性覆盖规则:
@Service@interface MyAnnotation{ String value() default "";}@Componnet@interface Service{String value() default "";}
以上注解都含有value属性,所以默认 MyAnnotation 会覆盖Service中的属性value。
- 显示覆盖的需求
@Service@interface MyAnnotation{ @AliasFor("value") String serviceValue() default "";}
使用@AliasFor
- @AliasFor是否可传递 这部分需要自己写代码测试。
参考
[1] 小马哥,《Spring Boot 编程思想》, 电子工业出版社, 2019.