前言

  • 上一章节介绍了Consul的一些基本概念,这一章节来介绍SpringCloud是怎样集成Consul的,按照SpringBoot的一贯作法来说这里会有一个starter pom

简单示例

  • 下面来集成Consul

    • 第一步:导入starter pom

      1
      2
      3
      4
      <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-consul-discovery</artifactId>
      </dependency>
    • 第二步:直接启动就可以了,使用起来十分方便

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      /**
      * @author songsy
      * @date 2019/8/14 17:43
      */
      @SpringCloudApplication
      public class UserApplication {

      public static void main(String[] args) {
      SpringApplication.run(UserApplication.class, args);
      }

      }

解析

  • 从上面可以看到要让SpringCloud集成Consul主要是一个spring-cloud-starter-consul-discoveryMaven依赖
spring-cloud-starter-consul-discovery
  • 我们先来看这个starter
  • 因为是个starter,所以我们关注pomspring.provides文件

    • pom文件: 可以看到有spring-cloud-starter-consulspring-cloud-consul-discovery两个依赖,除此之外还依赖了spring-cloud-netflix-corespring-cloud-starter-ribbon,这两个依赖是为了开启负债均衡吧

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      <?xml version="1.0" encoding="UTF-8"?>
      <project xmlns="http://maven.apache.org/POM/4.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <parent>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-consul</artifactId>
      <version>1.3.2.RELEASE</version>
      <relativePath>..</relativePath>
      </parent>
      <artifactId>spring-cloud-starter-consul-discovery</artifactId>
      <name>Spring Cloud Starter Consul Discovery</name>
      <description>Spring Cloud Starter Consul Discovery</description>
      <url>https://projects.spring.io/spring-cloud</url>
      <organization>
      <name>Pivotal Software, Inc.</name>
      <url>https://www.spring.io</url>
      </organization>
      <properties>
      <main.basedir>${basedir}/../..</main.basedir>
      </properties>
      <dependencies>
      <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-consul</artifactId>
      </dependency>
      <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-consul-discovery</artifactId>
      </dependency>
      <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-netflix-core</artifactId>
      </dependency>
      <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-ribbon</artifactId>
      </dependency>
      <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <!-- Only needed at compile time -->
      <scope>provided</scope>
      </dependency>
      <dependency>
      <groupId>joda-time</groupId>
      <artifactId>joda-time</artifactId>
      </dependency>
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      </dependencies>
      </project>
    • spring.provides

      1
      provides: spring-cloud-consul-discovery
  • 我们现在关注spring-cloud-starter-consulspring-cloud-consul-discovery这两个依赖

    • 1、spring-cloud-starter-consul,这里核心依赖是spring-cloud-consul-corecom.ecwid.consul:consul-api,第二包是consul依赖包

      • 打开pom.xml
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        <?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-consul</artifactId>
        <version>1.3.2.RELEASE</version>
        <relativePath>..</relativePath>
        </parent>
        <artifactId>spring-cloud-starter-consul</artifactId>
        <name>Spring Cloud Starter Consul</name>
        <description>Spring Cloud Starter Consul</description>
        <url>https://projects.spring.io/spring-cloud</url>
        <organization>
        <name>Pivotal Software, Inc.</name>
        <url>https://www.spring.io</url>
        </organization>
        <properties>
        <main.basedir>${basedir}/../..</main.basedir>
        </properties>
        <dependencies>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-commons</artifactId>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-context</artifactId>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-consul-core</artifactId>
        </dependency>
        <dependency>
        <groupId>com.ecwid.consul</groupId>
        <artifactId>consul-api</artifactId>
        </dependency>
        <!-- required by com.ecwid.consul but not as a pom dependency -->
        <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        </dependency>
        <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        </dependency>
        <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpcore</artifactId>
        </dependency>
        </dependencies>
        </project>
    • 2、spring-cloud-consul-discovery

      • 先看有什么
      • pom依赖

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89
        90
        91
        92
        93
        94
        95
        96
        97
        98
        99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        <modelVersion>4.0.0</modelVersion>

        <artifactId>spring-cloud-consul-discovery</artifactId>
        <packaging>jar</packaging>
        <name>Spring Cloud Consul Discovery</name>
        <description>Spring Cloud Consul Discovery</description>

        <parent>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-consul</artifactId>
        <version>1.3.2.RELEASE</version>
        <relativePath>..</relativePath>
        </parent>

        <dependencies>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-consul-core</artifactId>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-commons</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-context</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-client</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>com.ecwid.consul</groupId>
        <artifactId>consul-api</artifactId>
        <optional>true</optional>
        </dependency>
        <!-- required by com.ecwid.consul but not as a pom dependency -->
        <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpcore</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-netflix-core</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-archaius</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>com.netflix.ribbon</groupId>
        <artifactId>ribbon</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>com.netflix.ribbon</groupId>
        <artifactId>ribbon-core</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>com.netflix.ribbon</groupId>
        <artifactId>ribbon-httpclient</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>com.netflix.ribbon</groupId>
        <artifactId>ribbon-loadbalancer</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        <optional>true</optional>
        <exclusions>
        <exclusion>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        </exclusion>
        </exclusions>
        </dependency>
        <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <!-- Only needed at compile time -->
        <scope>provided</scope>
        </dependency>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        </dependency>
        <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <optional>true</optional>
        </dependency>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
        <optional>true</optional>
        </dependency>
        </dependencies>
      • spring.factories,这里我们看到了一些自动配置类,这个是SpringCloud集成Consul的关键

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
        org.springframework.cloud.consul.discovery.RibbonConsulAutoConfiguration,\
        org.springframework.cloud.consul.discovery.configclient.ConsulConfigServerAutoConfiguration,\
        org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration,\
        org.springframework.cloud.consul.serviceregistry.ConsulServiceRegistryAutoConfiguration,\
        org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration


        org.springframework.cloud.bootstrap.BootstrapConfiguration=\
        org.springframework.cloud.consul.discovery.configclient.ConsulDiscoveryClientConfigServiceBootstrapConfiguration
      • 其他代码

@EnableDiscoveryClient注解
  • @SpringCloudApplication注解里面可以看到默认有@EnableDiscoveryClient注解
1
2
3
4
5
6
7
8
9
10
11
12
/**
* @author Spencer Gibb
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
  • 我们现在看@EnableDiscoveryClient注解,查看注释可以知道这个注解开启了就会自动将本地服务注册到相应的注册中心
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 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(EnableDiscoveryClientImportSelector.class)
  • 可以看到这个类实现了ImportSelector接口,我们在之前的SpringBoot系列的@EnableAutoConfiguration自动配置章节就接触到了这个接口,ImportSelector接口的selectImports返回的数组(类的全类名)都会被注册到Spring容器中,所以可以通过这个方法来自定义注册哪些bean

  • 从下面代码可以看到String[]是只有一个org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration类,所以可以得到结果@EnableDiscoveryClient注解用于注册AutoServiceRegistrationConfiguration这个Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableDiscoveryClientImportSelector
extends SpringFactoryImportSelector<EnableDiscoveryClient> {

@Override
public String[] selectImports(AnnotationMetadata metadata) {
String[] imports = super.selectImports(metadata);

AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));

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]);
} else {
Environment env = getEnvironment();
if(ConfigurableEnvironment.class.isInstance(env)) {
ConfigurableEnvironment configEnv = (ConfigurableEnvironment)env;
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("spring.cloud.service-registry.auto-registration.enabled", false);
MapPropertySource propertySource = new MapPropertySource(
"springCloudDiscoveryClient", map);
configEnv.getPropertySources().addLast(propertySource);
}

}

return imports;
}

@Override
protected boolean isEnabled() {
return new RelaxedPropertyResolver(getEnvironment()).getProperty(
"spring.cloud.discovery.enabled", Boolean.class, Boolean.TRUE);
}

@Override
protected boolean hasDefaultFactory() {
return true;
}

}
  • 下面我们来关注org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration,这里是注册了AutoServiceRegistrationProperties配置类
1
2
3
4
5
6
7
8
/**
* @author Spencer Gibb
*/
@Configuration
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {
}

总结

  • spring-cloud-starter-consul-discovery利用了Maven传递依赖的功能定义了集成Consul所需的各种依赖,先备粮草
  • SpringCloud集成Consul过程就是注册bean的过程,具体实现还是通过spring.factoriesEnableAutoConfiguration自动配置来实现的