前言
最近,在看nacos配置管理以及服务注册与发现。在进行 SpringBoot整合nacos实现配置的动态变更及服务的注册与发现时,遇到了一些各种各样的坑,这里总结一下。
一、nacos配置管理
参考nacos官方文档: https://nacos.io/zh-cn/docs/quick-start-spring-boot.html
1.项目结构:
2.引入依赖包
此处要留意版本号问题。 版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本。
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-config-spring-boot-starter</artifactId>
<version>0.2.7</version>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-discovery-spring-boot-starter</artifactId>
<version>0.2.7</version>
</dependency>
3.配置bootstrap.yml文件
spring:
application:
name: nacos-demo-service
profiles:
active: local
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml #properties
namespace:
discovery:
server-addr: 127.0.0.1:8848
若IDEA新建bootstrap.yml文件不显示叶子图标,可参考: https://blog.csdn.net/weixin_42957931/article/details/115962689
4.启动本地的windows版nocos服务
我这里用到的是nacos-1.2.1版本。
5.浏览器访问nacos并新建配置
(1)访问url: http://127.0.0.1:8848/nacos/ (2)默认账号/密码:nacos / nacos 登录 (3)新建一个命名空间,命名空间ID不用填,会自动生成: (4)配置列表-新建一个项目的配置文件 我这里选择新建一个yaml配置文件: common.yaml配置文件内容:
user:
allName: HELLO
fullAge: 77
age: 23
name: shanxian
userInfo:
age: 55
name: zhushan
spring:
application:
name: nacos-demo-service
#服务器端口和上下文
server:
Port: 8088
servlet:
context-path: /project-dev
#数据库信息
spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
datasource:
master:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/sasac?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true
driver-class-name: com.mysql.cj.jdbc.Driver
slave_1:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/sasac?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true
driver-class-name: com.mysql.cj.jdbc.Driver
(5)更新bootstrap.yml文件
spring:
application:
name: nacos-demo-service
profiles:
active: local
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml #properties
namespace: 70aab5a7-759f-447d-8881-a2070611d1c3
shared-dataids: common.yaml
discovery:
server-addr: 127.0.0.1:8848
(6)创建TestController类写一个测试方法,验证配置信息获取与配置动态刷新:
package com.mybatisplus.controller;
import com.alibaba.nacos.api.annotation.NacosProperties;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.alibaba.nacos.spring.context.annotation.config.EnableNacosConfig;
import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource;
import com.mybatisplus.config.UserProperties;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/test")
@Api(tags = "测试接口")
@NacosPropertySource(dataId = "common.yaml" , groupId="DEFAULT_GROUP", autoRefreshed = true)
public class TestController {
@Autowired
private UserProperties userProperties;
@NacosValue(value = "${server.Port}",autoRefreshed = true)
private String port;
@NacosValue(value = "${user.allName}",autoRefreshed = true)
private String allName;
@NacosValue(value = "${user.fullAge}",autoRefreshed = true)
private String fullAge;
@NacosValue(value = "${userInfo.age}",autoRefreshed = true)
private String ageInfo;
@NacosValue(value = "${userInfo.name}",autoRefreshed = true)
private String nameInfo;
@GetMapping(value = "/config")
@ApiOperation(value = "配置信息获取")
public void getConfig(){
System.out.println("-----------user自动刷新配置---------");
System.out.println("端口:"+port);
System.out.println("年龄fullAge:"+fullAge);
System.out.println("姓名allName:"+allName);
System.out.println("-----------userInfo自动刷新配置---------");
System.out.println("userInfo年龄age:"+ageInfo);
System.out.println("userInfo姓名name:"+nameInfo);
System.out.println("-----------非自动刷新配置---------");
System.out.println("userProperties年龄age:"+userProperties.getAge());
System.out.println("userProperties姓名name:"+userProperties.getName());
System.out.println("------------------------------分割线-----------------------");
}
}
@NacosPropertySource注解作用于类上,用于指定配置源文件,autoRefreshed 属性用于配置是否动态刷新配置。 @NacosValue注解用于获取配置信息 对照组的属性类UserProperties如下:
package com.mybatisplus.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "user-info")
public class UserProperties {
private String name;
private String age;
private String allName;
public String getAllName() {
return allName;
}
public void setAllName(String allName) {
this.allName = allName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
6.启动项目
启动发现报错,找不到对应的配置文件信息: Injection of @com.alibaba.nacos.api.config.annotation.NacosValue dependencies is failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder ‘server.Port’ in value “${server.Port}” 查了很多博客,后来发现缺少配置文件: application.yml 和bootstrap.yml 的区别,不仅仅是优先级的问题。 SpringBoot 项目中如果没有依赖 spring-cloud-context 的话,是不会读取bootstrap.properties 文件。
也就是说,bootstrap.yml配置是SpringCloud项目才会用到的。 如果你的项目仅仅是一个SpringBoot项目,只会识别application.yml配置文件。
由于SpringCloud是基于SpringBoot构建的,所有SpringCloud项目两种文件都会识别,这个时候才有优先级的说法,SpringCloud项目是会优先读取bootstrap配置在读取application配置。
添加依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/>
</parent>
<!--需要引入该jar才能使bootstrap配置文件生效-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
如果报以下错误,说明springboot和SpringCloud版本号不匹配,尝试切换版本号!
或者添加如下依赖,也可以优先读取到bootstrap.yml配置信息。
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.0.1</version>
</dependency>
此处同样要注意版本号兼容的问题。 然后重启项目: 先postman调用一次测试接口,然后修改nacos配置工作台的yaml文件配置信息,再调用一次,观察自动刷新状况:
二、服务注册与发现
自动注册服务:
1.引入依赖
代码如下(示例):
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>nacos-discovery-spring-boot-starter</artifactId>
<version>0.2.7</version>
</dependency>
2.配置bootstrap.yml文件
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml #properties
namespace: 70aab5a7-759f-447d-8881-a2070611d1c3
shared-dataids: common.yaml
discovery:
server-addr: 127.0.0.1:8848
namespace: 70aab5a7-759f-447d-8881-a2070611d1c3
register:
groupName: DEFAULT_GROUP
autoRegister: true #自动注册服务到nacos
启动服务后,查看面板,发现本地服务已注册到nacos: 手动注册服务: 1.建一个DiscoveryController类用于查询服务:
package com.mybatisplus.controller;
import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("discovery")
public class DiscoveryController {
@NacosInjected
private NamingService namingService;
@RequestMapping(value = "/get", method = RequestMethod.GET)
@ResponseBody
public List<Instance> get(@RequestParam String serviceName) throws NacosException {
return namingService.getAllInstances(serviceName);
}
}
2.启动本地服务,调用:http://localhost:8088/project-dev/discovery/get?serviceName=example,此时返回为空 JSON 数组[]。
3.通过调用 Nacos Open API 向 Nacos server 注册一个名称为 example 服务: POST: http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=example&ip=127.0.0.1&port=8088
4.再次访问服务: GET : http://localhost:8088/project-dev/discovery/get?serviceName=example
总结
参考文章:
- https://blog.csdn.net/he__xu/article/details/120893044?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2aggregatepagefirst_rank_ecpm_v1~rank_v31_ecpm-3-120893044-null-null.pc_agg_new_rank&utm_term=bootstrap.yml%20%E9%85%8D%E7%BD%AE&spm=1000.2123.3001.4430
- https://www.jianshu.com/p/491db5791bf7?ivk_sa=1024320u
- https://blog.csdn.net/he__xu/article/details/120893044?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2aggregatepagefirst_rank_ecpm_v1~rank_v31_ecpm-3-120893044-null-null.pc_agg_new_rank&utm_term=bootstrap.yml%20%E9%85%8D%E7%BD%AE&spm=1000.2123.3001.4430
|