Spring Cloud之@EnableDiscoveryClient注解

为什么一个简单的Spring Boot项目增加一个Eureka依赖和配置,再加一个@EnableDiscoveryClient注解,就能通过Eureka服务器上注册或者消费服务呢?

Eureka的自动配置

先看EurekaClientAutoConfiguration类,从名字可以看出来这个类是用来自动配置Eureka的。

@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@ConditionalOnBean(EurekaDiscoveryClientConfiguration.Marker.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
@AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class,
        CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
@AutoConfigureAfter(name = "org.springframework.cloud.autoconfigure.RefreshAutoConfiguration")
public class EurekaClientAutoConfiguration {
    //
}

这个类在Condition满足时,会先实例化一个EurekaClient的配置EurekaClientConfigBean,在application.yml中关于eureka.client.xxx的配置都是来自这个类。

然后会实例化一个EurekaInstanceConfigBean实例,在application.yml中关于eureka.instance.xxx的配置都是来自这个类。

另外,还会根据@ConditionalOnBean(AutoServiceRegistrationProperties.class)决定是否实例化EurekaRegistrationEurekaAutoServiceRegistration类。

如何自动注册

先看看这个注解源码:

/**
 * Annotation to enable a DiscoveryClient implementation.
 * @author Spencer Gibb
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {

    /**
     * If true, the ServiceRegistry will automatically register the local server.
     */
    boolean autoRegister() default true;
}

也就比一般普通的注解多了一个@Import注解,而这个注解在Spring中主要作用就是导入资源。@Import注解的作用:
– 可以是一个普通的类,将其实例化为一个Bean
– 拥有@Configuration注解的类,将里面的@Bean全部实例化
– 可以是ImportSelector接口的子类,实例化该接口返回的全限定类名

所以,@EnableDiscoveryClient@Import会去实例化EnableDiscoveryClientImportSelector类,并执行其selectImports(AnnotationMetadata metadata)方法,因为EnableDiscoveryClientImportSelector类是ImportSelector接口的实现类。继承关系如图:

selectImports方法源码:

它首先是调用了父类的selectImports方法,然后再判断如果autoRegister属性为true,就把org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration字符串添加到importsList集合中;最后再将importsList集合转换成数组返回,整个过程结束。

再看看这个父类的方法里面做了什么:

首先,父类的构造器获取到了子类上面的EnableDiscoveryClient泛型类型:

protected SpringFactoryImportSelector() {
  this.annotationClass = (Class<T>) GenericTypeResolver
      .resolveTypeArgument(this.getClass(), SpringFactoryImportSelector.class);
}

然后selectImports方法通过EnableDiscoveryClient泛型类型获取到全部的factories:

// Find all possible auto configuration classes, filtering duplicates
List<String> factories = new ArrayList<>(new LinkedHashSet<>(SpringFactoriesLoader
    .loadFactoryNames(this.annotationClass, this.beanClassLoader)));

而这个loadFactoryNames方法就是获取jar包的META-INF/spring.factories文件,然后得到org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration字符串。

所以@Import(EnableDiscoveryClientImportSelector.class)EnableDiscoveryClientImportSelector最终返回的是一个包含org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfigurationorg.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration两个字符串的数组。

boolean autoRegister = attributes.getBoolean("autoRegister");

if (autoRegister) {
    List<String> importsList = new ArrayList<>(Arrays.asList(imports));
    importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
    imports = importsList.toArray(new String[0]);
}

从这段代码可以发现,自动注册是跟AutoServiceRegistrationConfiguration类有关系的,而这个类里面只有一个开启AutoServiceRegistrationProperties配置的功能

@Configuration
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
public class AutoServiceRegistrationConfiguration {
}

再回头看EurekaClientAutoConfiguration类:

AutoServiceRegistrationPropertiesBean存在时,就会实例化EurekaRegistrationEurekaAutoServiceRegistration

Spring Cloud自动配置的本质都是一样,通过@Configuration注解,再配合@Bean@Import和各种@ConditionalXXX等注解,实现属性的自动注入和Bean的实例化。

赞(0) 打赏
未经允许不得转载:当归笔记 » Spring Cloud之@EnableDiscoveryClient注解
分享到:

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用,就打赏一下作者吧~

支付宝扫一扫打赏

微信扫一扫打赏