SpringBoot2+gradle实现Consul注册中心+配置中心的学习笔记

背景:

  1. 为什么要研究较为冷门的Consul,是因为之前搭建的Eureka已经过时了,而且使用体验也很一般,虽然阿里出品的Nacos也很不错,可以完全取代Eureka,但是了解到Consul是用GO语言开发的,小巧轻便,占用内存很小(估计不超过50M),对比java的eureka和nacos单节点部署就占用800MB以上内存,我坚定地选择非java的Consul,事实上,我是越来越不喜欢java被spring绑架后变和越来越臃肿。
  2. Consul支持配置中心,能减少部署一个服务,这算也是Consul的一个优点。据说这是新版才实现的,之前是没有的。
  3. 我也是刚搭建成功,对Consul的认知水平很有限,只是小白一名,如有错误请多指教。
  4. 网上找到的consul文章都是用maven搭建的,没有找到gradle搭建的,但我坚决拥护gradle,所以只能自己先踩坑了,所以这应该是consul+gradle的首篇入门教程了。
  5. 配置中心搞了好久才实现,总结一些经验,避免后面的人重复踩坑。

启动Consul服务:

  1. 官方下载consul链接
  2. 执行consul.exe agent -dev

注册中心实现步骤:

  1. 创建3个gradle项目:consul-producer1,consul-producer2,consul-consumer
    SpringBoot2+gradle实现Consul注册中心+配置中心的学习笔记_第1张图片
  2. consul-producer1的build.gradle:
plugins {
    // Apply the java-library plugin to add support for Java Library
    id 'java-library'
}

repositories {
    jcenter()
}

dependencies {
    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    //以下是consul需要依赖的库,注意springboot和springcloud的版本的对应关系
    implementation 'org.springframework.boot:spring-boot-starter-actuator:2.1.8.RELEASE'
    implementation 'org.springframework.boot:spring-boot-starter-web:2.1.8.RELEASE'
    implementation 'org.springframework.cloud:spring-cloud-dependencies:Greenwich.SR5'
    implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery:2.1.5.RELEASE'
    implementation 'org.springframework.cloud:spring-cloud-starter-consul-config:2.1.5.RELEASE'
}
  1. consul-producer1的配置文件application.properties:
#以下是配置中心部分
#配置中心默认为启用
#spring.cloud.consul.config.enabled=true
#官方默认格式是yaml,但建议必填,移除后会报错
spring.cloud.consul.config.format=yaml
#key的路径最后部分,默认是data
#spring.cloud.consul.config.data-key=data
#key的路径开头第一段,默认为config
#spring.cloud.consul.config.prefix=config
#key的中间段,默认是spring.application.name值
#spring.cloud.consul.config.defaultContext=${spring.application.name}
  1. consul-producer1的启动主程序:ConsulProductApp.java:
package ConsulProducer1App;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableDiscoveryClient
@RestController

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

	@GetMapping("/student/info")
	public String studentInfo(){
		return "I am consul producer1";
	}
}
  1. 启动ConsulProducer1App,控制台日志显示:
:: Spring Boot ::       (v2.1.10.RELEASE)

2021-06-14 15:49:31.972  INFO 46508 --- [           main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-config/consul-producer1/'}]
2021-06-14 15:49:31.984  INFO 46508 --- [           main] ConsulProducter.ConsulProducer1App       : No active profile set, falling back to default profiles: default
2021-06-14 15:49:33.186  WARN 46508 --- [           main] o.s.boot.actuate.endpoint.EndpointId     : Endpoint ID 'service-registry' contains invalid characters, please migrate to a valid format.
2021-06-14 15:49:33.734  INFO 46508 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=fe42d923-d549-3c99-a2b5-90fc86b54220
2021-06-14 15:49:34.336  INFO 46508 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8082 (http)
2021-06-14 15:49:34.424  INFO 46508 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-06-14 15:49:34.424  INFO 46508 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.24]
2021-06-14 15:49:34.676  INFO 46508 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-06-14 15:49:34.676  INFO 46508 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2666 ms
2021-06-14 15:49:34.894  WARN 46508 --- [           main] c.n.c.sources.URLConfigurationSource     : No URLs will be polled as dynamic configuration sources.
2021-06-14 15:49:34.894  INFO 46508 --- [           main] c.n.c.sources.URLConfigurationSource     : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2021-06-14 15:49:34.932  INFO 46508 --- [           main] c.netflix.config.DynamicPropertyFactory  : DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@eb6ec6
2021-06-14 15:49:35.741  WARN 46508 --- [           main] c.n.c.sources.URLConfigurationSource     : No URLs will be polled as dynamic configuration sources.
2021-06-14 15:49:35.741  INFO 46508 --- [           main] c.n.c.sources.URLConfigurationSource     : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2021-06-14 15:49:36.038  INFO 46508 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2021-06-14 15:49:36.961  INFO 46508 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService 'configWatchTaskScheduler'
2021-06-14 15:49:36.996  INFO 46508 --- [           main] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService 'catalogWatchTaskScheduler'
2021-06-14 15:49:37.026  INFO 46508 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2021-06-14 15:49:37.372  INFO 46508 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8082 (http) with context path ''
2021-06-14 15:49:37.424  INFO 46508 --- [           main] o.s.c.c.s.ConsulServiceRegistry          : Registering service with consul: NewService{id='consul-producer1-8082', name='consul-producer1', tags=[secure=false], address='dev1', meta=null, port=8082, enableTagOverride=null, check=Check{script='null', interval='10s', ttl='null', http='http://dev1:8082/actuator/health', method='null', header={}, tcp='null', timeout='null', deregisterCriticalServiceAfter='null', tlsSkipVerify=null, status='null'}, checks=null}
2021-06-14 15:49:37.632  INFO 46508 --- [           main] ConsulProducter.ConsulProducer1App       : Started ConsulProducer1App in 8.653 seconds (JVM running for 9.316)
2021-06-14 15:49:37.920  INFO 46508 --- [nio-8082-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-06-14 15:49:37.922  INFO 46508 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2021-06-14 15:49:37.936  INFO 46508 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 14 ms

  1. consul-producer2参考consul-producer1,application.properties改端口为8003即可:
server.port=8083
  1. consul-consumer的build.gradle:
plugins {
    id 'java-library'
}

repositories {
    jcenter()
}

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery:2.0.0.RELEASE'
    implementation 'org.springframework.boot:spring-boot-starter-test:2.0.9.RELEASE'
    implementation 'org.springframework.boot:spring-boot-starter-web:2.0.9.RELEASE'
}
  1. consul-consumer项目的ConsulConsumerApp.java:
package ConsulConsumer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
@RestController
@Configuration

public class ConsulConsumerApp{

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

	@Bean
	 @LoadBalanced
	 public RestTemplate restTemplate(){
	 return new RestTemplate();
	 }
	
	@Autowired
	 RestTemplate restTemplate;
	 
	 @GetMapping("/consul/student/show")
	 public String version(){
	 //这里使用服务实例名调用REST接口
	 return restTemplate.getForObject("http://consul-producer1/student/info",String.class);
	 }
}

测试

成功启动ConsulProducer1App、ConsulProducer2App、ConsulConsumerApp之后,使用Postman或browser进行测试。

  1. ConsulConsumer测试地址:http://127.0.0.1:8084/consul/student/show
    浏览器页面轮流显示producer1和producer2的页面:
    在这里插入图片描述
    SpringBoot2+gradle实现Consul注册中心+配置中心的学习笔记_第2张图片
  2. 关闭ConsulProducer2App,检查当前状态http://127.0.0.1:8500/v1/agent/checks,Status状态已改为critical:
{
    "service:consul-producer1-8082": {
        "Node": "dev1",
        "CheckID": "service:consul-producer1-8082",
        "Name": "Service 'consul-producer1' check",
        "Status": "passing",
        "Notes": "",
        "Output": "HTTP GET http://dev1:8082/actuator/health: 200  Output: {\"status\":\"UP\"}",
        "ServiceID": "consul-producer1-8082",
        "ServiceName": "consul-producer1",
        "ServiceTags": [
            "secure=false"
        ],
        "Type": "http",
        "Definition": {},
        "CreateIndex": 0,
        "ModifyIndex": 0
    },
    "service:consul-producer1-8083": {
        "Node": "dev1",
        "CheckID": "service:consul-producer1-8083",
        "Name": "Service 'consul-producer1' check",
        "Status": "critical", //状态已改为critical
        "Notes": "",
        "Output": "Get \"http://dev1:8083/actuator/health\": dial tcp [fe80::4840:bbae:29ea:4852%以太网]:8083: connectex: No connection could be made because the target machine actively refused it.",
        "ServiceID": "consul-producer1-8083",
        "ServiceName": "consul-producer1",
        "ServiceTags": [
            "secure=false"
        ],
        "Type": "http",
        "Definition": {},
        "CreateIndex": 0,
        "ModifyIndex": 0
    }
}

SpringBoot2+gradle实现Consul注册中心+配置中心的学习笔记_第3张图片

继续访问http://127.0.0.1:8084/consul/student/show,就只返回"I am consul producer1"。
重新启动ConsulProducer2App.java成功后,大约过了30秒后,才能自动识别procducer2服务已上线,又能出现"我是product2"的返回了。
至此,consul的注册中心的搭建已成功实现。

再分享一个移除注册实例的方法,通过postman用put方式提交:
http://127.0.0.1:8500/v1/agent/service/deregister/consul-producer1-8084

参考链接:

  • 具有Consul的分布式配置
  • Consul移除不使用的服务(Deregister Service)

配置中心实现步骤:

  1. 在key/values添加一条记录:key为"config/consul-producer1/data",value建议使用yaml格式,因为能动态修改后能立即同步。效果如下:SpringBoot2+gradle实现Consul注册中心+配置中心的学习笔记_第4张图片
  2. bootstrap.xml的配置中心的相关配置:
#以下是配置中心部分
#配置中心默认为启用
#spring.cloud.consul.config.enabled=true
#官方默认格式是yaml,但建议必填,移除后会报错
spring.cloud.consul.config.format=yaml
#key的路径最后部分,默认是data
#spring.cloud.consul.config.data-key=data
#key的路径开头第一段,默认为config
#spring.cloud.consul.config.prefix=config
#key的中间段,默认是spring.application.name值
#spring.cloud.consul.config.defaultContext=${spring.application.name}
  1. consul-producer1项目增加一个配置类StudentConfig.java:

package ConsulProducter;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix="student")
public class StudentConfig{
	private String name;
	private int age;
	private String sex;

	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name=name;
	}
	public int getAge(){
		return age;
	}
	public void setAge(int age){
		this.age=age;
	}
	public String getSex(){
		return sex;
	}
	public void setSex(String sex){
		this.sex=sex;
	}
	@Override
	public String toString(){
		return "StudentConfig{"+"name='"+name+'\''+", age="+age+", sex='"+sex+'\''+'}';
	}
}
  1. ConsulProducer1App.java改为:
package ConsulProducter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Configuration
@SpringBootApplication
@EnableDiscoveryClient
@EnableAutoConfiguration
@RestController
@EnableConfigurationProperties({StudentConfig.class})

public class ConsulProducer1App{

  @Autowired
  private StudentConfig studentConfig;
	public static void main(String[] args){
		SpringApplication.run(ConsulProducer1App.class,args);
	}
	
	@GetMapping("/student/info")
	public String studentInfo(){
		return "studentName:"+studentName+" ,studentConfig="+studentConfig;
	}
	
	@Value("${studentName}")
	private String studentName;
	
	 @RequestMapping("/config")
   public String testConfig(){
       System.out.println(studentConfig.toString());
       return studentConfig.toString();
	 }
}
  1. http://127.0.0.1:8084/consul/student/show测试结果:
studentName:李小虎 ,studentConfig=StudentConfig{name='黄飞鸿', age=26, sex='男'}

在这里插入图片描述
6. 修改config/consul-producer1/data值:

studentName: 李双双
student:
  name: 李小龙
  age: 28
  sex:teacher:
 name: 叶问

SpringBoot2+gradle实现Consul注册中心+配置中心的学习笔记_第5张图片
7. 重新测试http://127.0.0.1:8084/consul/student/show,可以看到studentName的值没有同步修改,但studentConfig的值实现了同步修改:

studentName:李小虎 ,studentConfig=StudentConfig{name='李小龙', age=28, sex='男'}

在这里插入图片描述

参考:

SpringCloud使用Consul作为分布式配置中心

文章源码下载

consul+springboot+gradle-demo.zip

你可能感兴趣的:(consul,gradle,spring,boot,java)