本示例是基于spring-boot-2.6.3、windows10、nacos-server-2.1.0的环境下进行研究记录。
对于一些版本的区别,还请自行去查阅。尤其是spring-cloud和spring-cloud-alibaba的版本对应。
项目依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring-cloud-dependencies.version>2021.0.3</spring-cloud-dependencies.version>
<spring-cloud-alibaba-dependencies.version>2021.0.1.0</spring-cloud-alibaba-dependencies.version>
<spring-boot.version>2.6.3</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--服务注册发现和注册-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--配置中心依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--解决引入bootstrap.yml不生效问题-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--版本对应 https://start.spring.io/actuator/info-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
到此,我们基于spring-cloud的项目依赖就完成了。我们创建一个名为micro-svc-provider
的boot项目,引入上述配置,并以test环境为例展开。
接下来,我们在nacos-server中增加一个配置micro-svc-provider-test.yaml
配置,为啥名字是这样,可否是别的名字,这个后面[注释1]会逐步介绍。
配置管理
我们先来看一下效果,再一个个展开描述。
配置内容为yaml格式的信息
代码配置
在bootstrap.yml中配置如下
server:
port: 8081
logging:
level:
root: info
spring:
application:
name: micro-svc-provider
profiles:
active: test
并且,通过bootstrap.yml配置了服务注册和配置中心相关信息。可能你会问,为啥在bootstrap-test.yml中配置,而不是application-test.yml中配置。其实这跟配置加载顺序有关系,这里引用网上一段描述:
bootstrap.yml(bootstrap.properties)与application.yml(application.properties)执行顺序
加载顺序 bootstrap.yml > application.yml > application-{spring.profiles.active}.yml
所以,bootstrap.yaml更多的是配置一些不经常变化甚至不变化的属性。application.yaml属性文件可更灵活的配置一些属性。
在spring-cloud官方文档中,也有对于bootstrap和application的一段描述:
官网文档地址:https://cloud.spring.io/spring-cloud-static/Dalston.SR5/single/spring-cloud.html#_the_bootstrap_application_context
在bootstrap-test.yml中配置如下
# test环境
spring:
cloud:
nacos:
discovery: # 服务注册发现相关配置
server-addr: localhost:8848 # IP and port of the Nacos Server listener
service: ${spring.application.name} # Name the current service,default spring.application.name
group: DEFAULT_GROUP
heart-beat-interval: 5000
heart-beat-timeout: 15000
ip-delete-timeout: 30000
watch-delay: 10000
namespace: 59bf057a-84c7-48ca-88e0-9f4fdc14a098 # 不配置,可能注册不成功
enabled: true
username: nacos
password: nacos
config: # 配置中心相关配置
server-addr: localhost:8848
file-extension: yaml # 目前支持yaml、properties两种,其他不支持
group: DEFAULT_GROUP # 如果是默认group,这里可以不用配置,否则是必须得配置的
namespace: 59bf057a-84c7-48ca-88e0-9f4fdc14a098 # 不配置,可能加载不到配置
username: nacos
password: nacos
因为配置中心的data-id为micro-svc-provider-test.yaml
,所以这里指定了file-extension: yaml
,并且还要指定namespace
,否则配置中心信息可能读取不到。
:: Spring Boot :: (v2.6.3)
2022-07-15 11:26:37.907 WARN 25156 --- [ main] c.a.c.n.c.NacosPropertySourceBuilder : Ignore the empty nacos configuration and get it based on dataId[micro-svc-provider] & group[DEFAULT_GROUP]
2022-07-15 11:26:37.910 WARN 25156 --- [ main] c.a.c.n.c.NacosPropertySourceBuilder : Ignore the empty nacos configuration and get it based on dataId[micro-svc-provider.yaml] & group[DEFAULT_GROUP]
2022-07-15 11:26:37.919 INFO 25156 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-micro-svc-provider-test.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-micro-svc-provider.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-micro-svc-provider,DEFAULT_GROUP'}]
2022-07-15 11:26:37.929 INFO 25156 --- [ main] c.e.m.MicroSvcProviderApplication : The following profiles are active: test
2022-07-15 11:26:38.328 INFO 25156 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=9401bf5b-87c7-3ba8-99c9-b48c8864a8e6
2022-07-15 11:26:38.555 INFO 25156 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8081 (http)
2022-07-15 11:26:40.566 INFO 25156 --- [ main] com.alibaba.nacos.client.naming : [BEAT] adding beat: BeatInfo{port=8081, ip='172.30.0.1', weight=1.0, serviceName='DEFAULT_GROUP@@micro-svc-provider', cluster='DEFAULT', metadata={preserved.heart.beat.timeout=15000, preserved.ip.delete.timeout=30000, preserved.register.source=SPRING_CLOUD, preserved.heart.beat.interval=5000}, scheduled=false, period=5000, stopped=false} to beat map.
2022-07-15 11:26:40.566 INFO 25156 --- [ main] com.alibaba.nacos.client.naming : [REGISTER-SERVICE] 59bf057a-84c7-48ca-88e0-9f4fdc14a098 registering service DEFAULT_GROUP@@micro-svc-provider with instance: Instance{instanceId='null', ip='172.30.0.1', port=8081, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='DEFAULT', serviceName='null', metadata={preserved.heart.beat.timeout=15000, preserved.ip.delete.timeout=30000, preserved.register.source=SPRING_CLOUD, preserved.heart.beat.interval=5000}}
2022-07-15 11:26:40.569 INFO 25156 --- [ main] c.a.c.n.registry.NacosServiceRegistry : nacos registry, DEFAULT_GROUP micro-svc-provider 172.30.0.1:8081 register finished
2022-07-15 11:26:40.945 INFO 25156 --- [g.push.receiver] com.alibaba.nacos.client.naming : received push data: {"type":"dom","data":"{\"name\":\"DEFAULT_GROUP@@micro-svc-provider\",\"clusters\":\"DEFAULT\",\"cacheMillis\":10000,\"hosts\":[{\"instanceId\":\"172.30.0.1#8081#DEFAULT#DEFAULT_GROUP@@micro-svc-provider\",\"ip\":\"172.30.0.1\",\"port\":8081,\"weight\":1.0,\"healthy\":true,\"enabled\":true,\"ephemeral\":true,\"clusterName\":\"DEFAULT\",\"serviceName\":\"DEFAULT_GROUP@@micro-svc-provider\",\"metadata\":{\"preserved.heart.beat.timeout\":\"15000\",\"preserved.ip.delete.timeout\":\"30000\",\"preserved.register.source\":\"SPRING_CLOUD\",\"preserved.heart.beat.interval\":\"5000\"},\"instanceHeartBeatInterval\":5000,\"instanceHeartBeatTimeOut\":15000,\"ipDeleteTimeout\":30000}],\"lastRefTime\":1657855600944,\"checksum\":\"\",\"allIPs\":false,\"reachProtectionThreshold\":false,\"valid\":true}","lastRefTime":146987339679400} from /172.30.0.1
2022-07-15 11:26:40.961 INFO 25156 --- [g.push.receiver] com.alibaba.nacos.client.naming : new ips(1) service: DEFAULT_GROUP@@micro-svc-provider@@DEFAULT -> [{"instanceId":"172.30.0.1#8081#DEFAULT#DEFAULT_GROUP@@micro-svc-provider","ip":"172.30.0.1","port":8081,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"DEFAULT","serviceName":"DEFAULT_GROUP@@micro-svc-provider","metadata":{"preserved.heart.beat.timeout":"15000","preserved.ip.delete.timeout":"30000","preserved.register.source":"SPRING_CLOUD","preserved.heart.beat.interval":"5000"},"ipDeleteTimeout":30000,"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000}]
2022-07-15 11:26:40.966 INFO 25156 --- [g.push.receiver] com.alibaba.nacos.client.naming : current ips:(1) service: DEFAULT_GROUP@@micro-svc-provider@@DEFAULT -> [{"instanceId":"172.30.0.1#8081#DEFAULT#DEFAULT_GROUP@@micro-svc-provider","ip":"172.30.0.1","port":8081,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"DEFAULT","serviceName":"DEFAULT_GROUP@@micro-svc-provider","metadata":{"preserved.heart.beat.timeout":"15000","preserved.ip.delete.timeout":"30000","preserved.register.source":"SPRING_CLOUD","preserved.heart.beat.interval":"5000"},"ipDeleteTimeout":30000,"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000}]
2022-07-15 11:26:41.211 INFO 25156 --- [ main] c.e.m.MicroSvcProviderApplication : Started MicroSvcProviderApplication in 5.414 seconds (JVM running for 6.635)
2022-07-15 11:26:41.215 INFO 25156 --- [ main] c.a.n.client.config.impl.ClientWorker : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [subscribe] micro-svc-provider.yaml+DEFAULT_GROUP+59bf057a-84c7-48ca-88e0-9f4fdc14a098
2022-07-15 11:26:41.215 INFO 25156 --- [ main] c.a.nacos.client.config.impl.CacheData : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider.yaml, group=DEFAULT_GROUP, cnt=1
2022-07-15 11:26:41.216 INFO 25156 --- [ main] c.a.c.n.refresh.NacosContextRefresher : listening config: dataId=micro-svc-provider.yaml, group=DEFAULT_GROUP
2022-07-15 11:26:41.217 INFO 25156 --- [ main] c.a.n.client.config.impl.ClientWorker : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [subscribe] micro-svc-provider-test.yaml+DEFAULT_GROUP+59bf057a-84c7-48ca-88e0-9f4fdc14a098
2022-07-15 11:26:41.217 INFO 25156 --- [ main] c.a.nacos.client.config.impl.CacheData : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider-test.yaml, group=DEFAULT_GROUP, cnt=1
2022-07-15 11:26:41.218 INFO 25156 --- [ main] c.a.c.n.refresh.NacosContextRefresher : listening config: dataId=micro-svc-provider-test.yaml, group=DEFAULT_GROUP
2022-07-15 11:26:41.218 INFO 25156 --- [ main] c.a.n.client.config.impl.ClientWorker : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [subscribe] micro-svc-provider+DEFAULT_GROUP+59bf057a-84c7-48ca-88e0-9f4fdc14a098
2022-07-15 11:26:41.218 INFO 25156 --- [ main] c.a.nacos.client.config.impl.CacheData : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider, group=DEFAULT_GROUP, cnt=1
2022-07-15 11:26:41.218 INFO 25156 --- [ main] c.a.c.n.refresh.NacosContextRefresher : listening config: dataId=micro-svc-provider, group=DEFAULT_GROUP
2022-07-15 11:27:26.577 INFO 25156 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-07-15 11:27:26.577 INFO 25156 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2022-07-15 11:27:26.578 INFO 25156 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
从以上输出日志中可以看出,在启动时,对于配置中心,会有三种名称的配置加载,这也就解释了上述提到了[注释1]命名可以是哪些。具体三种名字如下:
[fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider-test.yaml, group=DEFAULT_GROUP, cnt=1
监测配置变化 listening config: dataId=micro-svc-provider-test.yaml, group=DEFAULT_GROUP
[fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider, group=DEFAULT_GROUP, cnt=1
监测配置变化 listening config: dataId=micro-svc-provider, group=DEFAULT_GROUP
[fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider.yaml, group=DEFAULT_GROUP, cnt=1
监测配置变化 listening config: dataId=micro-svc-provider.yaml, group=DEFAULT_GROUP
所以,在配置时,需要注意哪些配置放在哪里合适。否则多个配置文件生效造成配置干扰,排查起来会很崩溃。
在application-test.yml中配置
这里可以配置跟业务相关的配置,有别于bootstrap.yml中的配置信息。比如
# 自定义其他信息
env: test-application-provider
来个栗子
@RefreshScope // 使得配置更新生效,也是cloud中的功能
@RestController
public class EchoController {
@Value(value = "${msg:null}") // 这里需要注意的是需要给默认值,否则启动时报错
private String msg;
@Value("${env:null}") // 这里需要注意的是需要给默认值,否则启动时报错
private String env;
@GetMapping(value = "/echo/{string}")
public String echo(@PathVariable String string) {
return env + ":" + msg + " from micro-svc-provider " + string;
}
}
这里涉及到两个点需要提一下:
1、@RefreshScope
:使得配置更新生效,也是cloud中的功能
2、@Value("${env:null}")
:这里需要注意的是需要给默认值,否则启动时报错,这里用来测试application-test.yml中的配置是否生效用的。而@Value(value = "${msg:null}")
是测试nacos配置是否生效用的。
运行
将项目运行起来后,通过访问 http://localhost:8081/echo/ssss,正常情况下,会输出:
test-application-provider:from-micro-svc-provider-test.yaml-modified from micro-svc-provider ssss
其中,test-application-provider
来自于application-test.yml配置
from-micro-svc-provider-test.yaml-modified
:来自于nacos配置中心
到此,我们基于配置中心的配置读取就完成,对于配置更新和实时更新可以自行测试。因为配置了@RefreshScope
,所以更新会即时同步的。
服务注册发现
上面,简单介绍了服务配置相关的设置和项目集成。接下来我们继续下一部分功能,即服务注册和发现。
仔细阅读的朋友应该发现了,上面在bootstrap-test.yml
中已经配置了出config
之外的discovery
的配置节点。这个节点就是服务注册发现相关的配置。是不是也挺简单的。
《服务管理-提供方》
配置完discovery节点,项目运行起来后,就可以在服务管理-服务列表内看到服务信息了。
这里涉及到一些保护阈值、服务的心跳时间等等配置,具体一些细节可以参考官方文档研读。也可以翻阅源码com.alibaba.cloud.nacos.NacosDiscoveryProperties
,可以看到很多属性serverAddr, username, password, endpoint, namespace, watchDelay, logName, service, weight, clusterName, group, namingLoadCacheAtStart, metadata, registerEnabled, ip, networkInterface,port, secure, accessKey, secretKey, heartBeatInterval, heartBeatTimeout,ipDeleteTimeout, instanceEnabled, ephemeral, failureToleranceEnabled,failFast
服务消费方
参考上述micro-svc-provider,在创建一个micro-svc-consumer作为服务消费方。
其他一模一样,更改一个项目名称就行了,EchoController内容如下:
@RefreshScope
@RestController
public class EchoController {
// 客户端负载均衡器
@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private RestTemplate restTemplate;
@Value("${spring.application.name}")
private String appName;
@GetMapping("/echo/app-name")
public String echoAppName() {
//Access through the combination of LoadBalanceClient and RestTemplate
ServiceInstance serviceInstance = loadBalancerClient.choose(Consts.PROVIDER_SVC_ID);
String path = String.format("http://%s:%s/echo/%s", serviceInstance.getHost(), serviceInstance.getPort(), appName);
System.out.println("request path:" + path);
return restTemplate.getForObject(path, String.class);
}
}
现在我们启动两个服务提供方实例,端口分别是8081、8079;而消费方实例端口为8082:
【from micro-svc-provider】env=test-application-provider,msg=from-micro-svc-provider-test.yaml-modified,port=8081,param=micro-svc-consumer
【from micro-svc-provider】env=test-application-provider,msg=from-micro-svc-provider-test.yaml-modified,port=8079,param=micro-svc-consumer
可以看到provider被轮询方式请求了。如果不想被轮询可以配置其他策略,也可以通过权重进行调整流量倾斜。
至此,我们本篇入门笔记就结束了。其中涉及的点比较简单,一些深入细节等以后随着使用的深入,在开新篇记录。
总结
大概总结下来,需要注意的内容如下:
1、spring-cloud 和spring-clod-alibaba版本对齐问题
2、spring-cloud 配置中心请求配置放在bootstrap-{env}.yml内,否则可能会读取不到配置
3、config和discovery配置时,需要注意相关属性
4、注解@Value
的默认值设置,否则启动时可能会报错
5、订阅者名称显示unknown的话,在项目启动参数中设置-Dproject.name=xxx
解决
references
文章评论