關於 spring 註解驅動編程

Stereotype Annotations

本文爲讀書筆記,如需深刻了解,請深刻文末參考html

@Component 以及其派生類是如何被掃描加載的?

spring3.0以前:java

  1. 配置spring <component-scan basePackage: /> xml 中這一配置的處理原理:Extensible XML authoring

好比:spring

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @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)編程

由於 @Component 註解的信息也會被MetadataReader讀取到,因此包含@Conponent的類也會被加載。ide

// 默認filter
protected void registerDefaultFilters() {
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		// .....
}

知道原理以後,spring提供了可擴展,支持增長Typefilter,這樣就不須要依賴spring的 @Component 註解了。測試

Dubbo 2.5.8 @Service的實現也是如此,請參考: ServiceAnnotationBeanPostProcessor.this

多層次派生的問題

@Repository
--@MyANNOTATION
----@Component

兩層以上能支持嗎,怎麼支持?

關鍵class AnnotationAttributesReadingVisitor. 結論:spring2 支持1層,spring3,支持兩層,spring4支持多層。spa

組合 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.net

<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 {
}

看源碼:

  1. cache pointcut: CacheOperationSourcePointcut -> CacheOperationSource -> AnnotatedElementUtils(支持解析 組合annotation)

  2. cahce advice: AbstractBeanFactoryPointcutAdvisor

  3. proxy bean: CacheProxyFactoryBean 另外再額外問題,CacheProxyFactoryBean何時加載?

因此是否支持組合註解,由該註解的處理類決定。

咱們猜想spring會解析classpath下全部的註解,才能爲其建立代理類。

使用 spring @AliasFor

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface AliasFor {
    @AliasFor("attribute")
    String value() default "";

    @AliasFor("value")
    String attribute() default "";

    Class<? extends Annotation> 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.

  1. 默認同名屬性覆蓋規則:
@Service
@interface MyAnnotation{
 String value() default "";
}

@Componnet
@interface Service{
String value() default "";
}

以上註解都含有value屬性,因此默認 MyAnnotation 會覆蓋Service中的屬性value。

  1. 顯示覆蓋的需求
@Service
@interface MyAnnotation{
	@AliasFor("value")
   String serviceValue() default "";
}

使用@AliasFor

  1. @AliasFor是否可傳遞 這部分須要本身寫代碼測試。

參考

[1] 小馬哥,《Spring Boot 編程思想》, 電子工業出版社, 2019.

相關文章
相關標籤/搜索