Spring Cloud Consul 实现服务注册和发现
每天学习一点点 编程PDF电子书免费下载: http://www.shitanlife.com/code
Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具,它为基于 JVM 的云应用开发中涉及的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。通过 Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
Spring Cloud 包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config、Spring Cloud Netflix、Spring Cloud CloudFoundry、Spring Cloud AWS、Spring Cloud Security、Spring Cloud Commons、Spring Cloud Zookeeper、Spring Cloud CLI 等项目。
项目地址:https://github.com/yuezhongxin/spring-cloud-consul-sample
ASP.NET Core 2.0 & Docker & Consul 的实现:https://github.com/yuezhongxin/HelloDocker.Sample
目前的测试站点,使用 ASP.NET Core 结合 Conusl 和 Fabio 搭建的微服务集群,因为各服务之间的通信基于 HTTP REST 协议,所以服务的实现可以跨语言,下面我们就开发一个 Spring Boot 服务,然后使用 Spring Cloud Consul 将服务注册到已有的集群中。
Java 开发工具我选用的 IntelliJ IDEA(MacOS 安装教程),目前使用很好(Color Scheme 使用系统的 Darcula,字体大小 14),Java SDK 需要额外下载安装(我安装的版本 10)。
因为第一次使用 IntelliJ IDEA,下面我把创建项目的过程,贴详细一点。
首先,创建项目(选择“Spring Initializr”,Spring Boot 项目),默认选择 Java SDK 10:
然后填写项目的基本信息(Artifact 为"spring-cloud-consul-sample",其他为默认):
注:Maven 是一个项目管理和构建工具,包含三个关键组件:项目对象模型(POM)、依赖项管理模型、构建生命周期和阶段。
Group ID 和 Artifact ID 的区别,如果把 Group ID 看作是公司,那 Artifact ID 就可以看作是公司部门,有点类似于 .NET 中的解决方案和类库的关系,比如 Spring Cloud 项目的 Group ID 为org.springframework.cloud
,Spring Cloud Consul 的 Artifact ID 为spring-cloud-starter-consul-discovery
。
下面选择创建 Spring Boot 项目类型(选择 Web 依赖项):
然后填写项目名称和项目目录:
然后点击“Finish”,就完成啦。
像开发 ASP.NET Core 应用程序一样,我们需要先引用各种程序包,Spring Boot 项目也是一样,因为使用 Maven 进行依赖管理,我们需要在pom.xml
中配置依赖关系,配置如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-consul-dependencies</artifactId>
<version>2.0.0.M7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
引用spring-cloud-starter-consul-discovery
对应 Spring Cloud Consul,引用spring-boot-starter-actuator
用作健康检查(地址/actuator/health
),另外 Actuator 还支持项目的监控和管理。
这里再说下节点的作用:
parent
:父引用配置,会继承父引用的配置。dependencies
:当前引用配置,如果父引用配置了,子项目会自动引用。dependencyManagement
:当然引用配置,如果父引用配置了,子项目不会自动引用,子项目只要用到的时候引用,不需要配置版本号。
然后再贴一下SpringCloudConsulSampleApplication.java
的代码:
package com.example.springcloudconsulsample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.discovery.DiscoveryClient;
@EnableDiscoveryClient
@RestController
@SpringBootApplication
public class SpringCloudConsulSampleApplication {
@Autowired
private DiscoveryClient discoveryClient;
/**
* 获取所有服务
*/
@RequestMapping("/services")
public Object services() {
return discoveryClient.getServices();
}
@RequestMapping("/home")
public String home() {
return "Hello World";
}
public static void main(String[] args) {
SpringApplication.run(SpringCloudConsulSampleApplication.class, args);
}
}
增加@EnableDiscoveryClient
注解,项目启动的时候,会注册当前 Spring Boot 服务。
在使用 ASP.NET Core 注册服务的时候,配置信息会填写在代码中(如服务名称和端口等,当然也可以在配置文件),然后使用 Consul 组件注册服务(调用 Consul HTTP REST)。
Spring Cloud Consul 注册服务的话,需要添加配置文件(Spring Boot 项目资源文件在 resources 目录下)。
application.properties
中添加配置:
spring.application.name=spring-boot-service
然后添加application.yml
配置文件:
debug: true
server:
port: 24543
spring:
cloud:
consul:
host: 127.0.0.1
port: 8500
discovery:
register: true
hostname: 10.9.10.215
serviceName: ${spring.application.name}
healthCheckPath: /actuator/health
healthCheckInterval: 15s
tags: urlprefix-/${spring.application.name}
instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
上面配置需要再详细说明说明下:
debug
配置是否调试模式,如果打包发布的话,需要设置为false
。server.port
配置的是 Spring Boot 服务的端口。spring.cloud.consul.host/port
配置的是本地 Consul 的地址和端口(Server 节点和 Client 节点都可以),Spring Cloud Consul 会调用 Consul HTTP REST 接口,进行服务注册。spring.cloud.consul.discovery.true
配置启动是否注册服务,spring.cloud.consul.discovery.hostname
配置 Spring Boot 服务的主机地址,也可以不进行配置,默认本机地址。spring.cloud.consul.discovery.serviceName
配置 Consul 注册的服务名称,${spring.application.name}
变量是我们上面application.properties
配置文件中添加的配置。spring.cloud.consul.discovery.healthCheckPath
配置 Consul 健康检查地址,Actuator 组件帮我们进行了实现,所以我们不需要额外的实现,地址在服务启动的时候,打印信息里面可以看到。spring.cloud.consul.discovery.healthCheckInterval
配置 Consul 健康检查频率,也就是心跳频率。spring.cloud.consul.discovery.tags
配置 Consul 注册服务的 Tags,设置为urlprefix-/serviceName
的格式,是自动注册到 Fabio 集群中。spring.cloud.consul.discovery.instanceId
配置 Consul 注册服务 ID。
上面的工作做完之后,我们还需要在本地启动 Consul 和 Fabio,参考:Mac OS、Ubuntu 安装及使用 Consul
然后我们就可以直接使用 IntelliJ IDEA 调试项目了,按Shift + F9
进行调试。
上面说到 Actuator 的打印信息:
2018-03-28 10:09:54.645 INFO 63482 --- [ main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/health],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
2018-03-28 10:09:54.646 INFO 63482 --- [ main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/info],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>)
2018-03-28 10:09:54.647 INFO 63482 --- [ main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto protected java.util.Map<java.lang.String, java.util.Map<java.lang.String, org.springframework.boot.actuate.endpoint.web.Link>> org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.links(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
或者我们也可以使用 Maven 打包发布,然后使用命令启动服务。使用 IntelliJ IDEA 中的 Maven 进行打包,或者使用 Maven 命令打包都可以,这边我们使用Maven 命令进行打包。
在我们安装 IntelliJ IDEA 的时候,Maven 自动安装了,但直接敲mvn -v
会发现命令找不到,需要我们配置一下环境变量。
我自己的 Maven 文件目录是/Applications/IntelliJ IDEA.app/Contents/plugins/maven/lib/maven3
,可以在 IntelliJ IDEA 的配置设置中找到,然后我们执行下面的命令:
$ export M2_HOME="/Applications/IntelliJ IDEA.app/Contents/plugins/maven/lib/maven3" &&
export PATH=$PATH:$M2_HOME/bin &&
chmod a+x "/Applications/IntelliJ IDEA.app/Contents/plugins/maven/lib/maven3/bin/mvn"
然后检查下 Maven 命令是否生效:
$ mvn -v
Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T00:41:47+08:00)
Maven home: /Applications/IntelliJ IDEA.app/Contents/plugins/maven/lib/maven3
Java version: 10, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk-10.jdk/Contents/Home
Default locale: zh_CN_#Hans, platform encoding: UTF-8
OS name: "mac os x", version: "10.13.2", arch: "x86_64", family: "mac"
然后我们修改application.yml
中的debug:false
,使用 Maven 进行打包(目录切换到pom.xml
平级):
$ mvn clean package -Dmaven.test.skip=true
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building spring-cloud-consul-sample 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:3.0.0:clean (default-clean) @ spring-cloud-consul-sample ---
[INFO] Deleting /Users/xishuai/Documents/项目文件/测试项目/spring-cloud-consul-sample/target
[INFO]
[INFO] --- maven-resources-plugin:3.0.1:resources (default-resources) @ spring-cloud-consul-sample ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ spring-cloud-consul-sample ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/xishuai/Documents/项目文件/测试项目/spring-cloud-consul-sample/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.0.1:testResources (default-testResources) @ spring-cloud-consul-sample ---
[INFO] Not copying test resources
[INFO]
[INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ spring-cloud-consul-sample ---
[INFO] Not compiling test sources
[INFO]
[INFO] --- maven-surefire-plugin:2.20.1:test (default-test) @ spring-cloud-consul-sample ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ spring-cloud-consul-sample ---
[INFO] Building jar: /Users/xishuai/Documents/项目文件/测试项目/spring-cloud-consul-sample/target/spring-cloud-consul-sample-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.0.0.RELEASE:repackage (default) @ spring-cloud-consul-sample ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.815 s
[INFO] Finished at: 2018-03-28T10:26:46+08:00
[INFO] Final Memory: 30M/114M
[INFO] ------------------------------------------------------------------------
生成的 jar 程序包,会在 target 目录下,文件为spring-cloud-consul-sample-0.0.1-SNAPSHOT.jar
(格式为项目名 + 版本号
),然后我们可以直接启动服务了:
$ java -jar target/spring-cloud-consul-sample-0.0.1-SNAPSHOT.jar
2018-03-28 10:33:31.750 INFO 63875 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2b662a77: startup date [Wed Mar 28 10:33:31 CST 2018]; root of context hierarchy
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils$1 (jar:file:/Users/xishuai/Documents/项目文件/测试项目/spring-cloud-consul-sample/target/spring-cloud-consul-sample-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/spring-core-5.0.4.RELEASE.jar!/) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of org.springframework.cglib.core.ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
2018-03-28 10:33:31.971 INFO 63875 --- [ main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2018-03-28 10:33:32.015 INFO 63875 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'configurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$4d45e598] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.0.RELEASE)
查看健康检查是否成功:
查看 Consul 是否服务注册成功:
查看 Fabio 集群是否包含服务:
服务注册成功之后,我们可以手动进行发现服务,或者通过 Spring Cloud Ribbon/Feign 组件进行发现,并提供负载均衡功能(类似于 Fabio 功能),后面再研究下。
参考资料:
- ameizi/spring-cloud-consul-example
- Spring Cloud构建微服务架构:服务注册与发现(Eureka、Consul)
- Spring Cloud Consul
- Spring Cloud Consul
- 使用 Spring Cloud Consul 实现服务的注册和发现
- Service Discovery with Consul
- spring-cloud-consul/spring-cloud-consul-sample
- Spring Boot Actuator 监控端点小结
- Spring Cloud(二)Consul 服务治理实现(推荐)
- 构建微服务(二)服务注册与发现
- springboot(十二):springboot 如何测试打包部署(推荐)
- springcloud(一):大话 Spring Cloud(推荐)