@AliasFor 注解


Spring 框架提供了很豐富的注解可以讓我們很方便的進行 Spring 配置,今天要講的注解——@AliasFor之前你可能並沒有關注過,因為平時開發時我們的確不太會用到。

我關注到這個注解是因為我經常翻看 Spring 的源代碼,在 Spring 提供的注解中大量的用到了這個注解,對這個注解不熟悉的話會影響你對代碼的判斷,而且有些代碼看的總是似懂非懂的,很難受(強迫症,哈哈),比如說下面這段代碼。

@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 {
    
	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};
    
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;

}

上面的代碼大致能“猜測”出 @AliasFor 是為了屬性起別名,但是 @AliasFor 的使用場景,使用方式,實現原理是什么?這博客就簡單介紹下。

@AliasFor 注解的幾種使用方式

1. 在同一個注解中顯示使用,將注解中的多個屬性互相設置別名

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    
	@AliasFor("path")
	String[] value() default {};

	@AliasFor("value")
	String[] path() default {};
    
    //...
}

為什么要給 value 屬性和 path 屬相互相設置別名也是有原因的。我們知道在 Spring 中給 value 屬性設置值是可以省略屬性的,比如可以寫成:

RequestMapping("/foo")

這樣寫比較簡潔,但是這樣可讀性不高,我們並不知道 value 屬性代表什么意思。如果給這個屬相設置一個 path 別名的話我們就知道這個是在設置路徑。

但是要注意一點,@AliasFor 標簽有一些使用限制:

  • 互為別名的屬性屬性值類型,默認值,都是相同的;
  • 互為別名的注解必須成對出現,比如 value 屬性添加了@AliasFor(“path”),那么 path 屬性就必須添加@AliasFor(“value”);
  • 另外還有一點,互為別名的屬性必須定義默認值。

那么如果違反了別名的定義,在使用過程中就會報錯。

2. 給元注解中的屬性設定別名

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

	@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};
    
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};
    //...
}

我們來看 @SpringBootApplication 這個注解,這個注解是有其他幾個注解“組合”而成的。下面的代碼就是在給@ComponentScan 注解的basePackages屬性設置別名scanBasePackages。如果不設置attribute屬性的話就是在給元注解的同名屬性設置別名。

@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};

這種使用方式的好處是可以將幾個注解的功能組合成一個新的注解。

@AliasFor 的實現代碼

貼大片代碼的事就不干了。@AliasFor 的具體實現在AnnotationUtils.findAnnotation 中,代碼大家自己翻看吧。


參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM