@EnableXXX 在工作中经常使用到,意味着开启某功能, 使用简单,那么@EnableXXX 到底干了那些事情呢。
@EnableXXX -------> @Import(A.class)
要实现某功能,则需要导入指定的class(es) 。
A为Configuration类
或者 A implements ImportBeanDefinitionRegistrar
或者 A extends SpringFactoryImportSelector
或者 A extends AdviceModeImportSelector
场景依次编号为1 2 3 4.
场景1 : 直接指定Configuration 类 @EnableZuulProxy 则意味着会自动注册 ZuulProxyConfiguration 定义的bean 。
@EnableCircuitBreaker @EnableDiscoveryClient @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(ZuulProxyConfiguration.class) public @interface EnableZuulProxy { }
场景2: 找到指定package内有特定声明的class,实例化然后注册到 BeanDefinitionRegistry。
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(FeignClientsRegistrar.class) public @interface EnableFeignClients {
FeignClientsRegistrar 会登记所有 @FeignClient 声明的客户端。 Registrar 登记员。。。
场景3: 场景3比场景1稍微含蓄一点,复杂一点。
根据 spring.factories 的配置找到相应的 Configuration 类 , 然后注册相应的bean 。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(EnableDiscoveryClientImportSelector.class) public @interface EnableDiscoveryClient {
@EnableHystrix和@EnableCircuitBreaker是等价的 (当你的pom文件中只引入了一种CircuitBreake实现时)
@EnableEurekaClient和EnableDiscoveryClient是等价的 (当你的pom文件中只引入了一种DiscoveryClient实现时)
具体实现: 根据key 查找相应的Configuration 类。 key 为最终的 annotationClass。
@Override public String[] selectImports(AnnotationMetadata metadata) {
if (!isEnabled()) {
return new String[0];
}
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(this.annotationClass.getName(), true));
Assert.notNull(attributes, "No " + getSimpleName() + " attributes found. Is "
+ metadata.getClassName() + " annotated with @" + getSimpleName() + "?");
// Find all possible auto configuration classes, filtering duplicates
List
if (factories.size() > 1) { // there should only ever be one DiscoveryClient, but there might be more than // one factory log.warn("More than one implementation " + "of @" + getSimpleName() + " (now relying on @Conditionals to pick one): " + factories); }
return factories.toArray(new String[factories.size()]); }
public static List
这里出现了熟悉的ClassLoader 。
原来 ClassLoader 除了能 loadClass 之外,还能 getResources 。
场景4 : 实现了aop 功能。 。。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(CachingConfigurationSelector.class) public @interface EnableCaching {
相关联的 Configuration
场景3和场景4 总归都是实现了 ImportSelector 接口。
public interface ImportSelector {
/** _ * Select and return the names of which class(es) should be imported based on * the {__@link AnnotationMetadata} of the importing @{__@link Configuration} class. _ */ String[] selectImports(AnnotationMetadata importingClassMetadata); }
大概的意思翻译一下: 要实现XXX功能, 则需要加载那些_Configuration 类 。_
Configuration 的前生就是Spring项目中的 xml 文件 。