1.1 https://github.com/alibaba/Nacos
2.1 一句话: Nacos 就是注册中心[替代Eureka]+配置中心[替代Config]
2.2 Nacos:Dynamic Naming and Configuration Service
2.3 Nacos:架构理论基础: CAP 理论(支持AP 和CP, 可以切换)
3.1 下载: https://github.com/alibaba/nacos/releases/tag/1.2.1
3.2 环境要求: Java8/Maven 3.2.x+
3.3 解压,运行bin/startup.cmd
3.4 浏览器http://localhost:8848/nacos
3.5 用户名/密码为nacos
修改pom.xml, 加入spring-cloud-alibaba 依赖
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.17version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
<dependency>
<groupId>com.hspedu.springcloudgroupId>
<artifactId>e_commerce_center-common-apiartifactId>
<version>${project.version}version>
dependency>
dependencies>
将member-service-provider-10000 的application.xml 拷贝过来,修改即可
server:
port: 10004
spring:
application:
name: member-service-nacos-provider #配置应用的名称
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/e_commerce_center_db?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username: root
password: 自己的密码
#配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos Server的地址
#配置暴露所有的监控点
management:
endpoints:
web:
exposure:
include: '*'
mybatis:
mapper-locations: classpath:mapper/*.xml #指定mapper.xml文件位置
type-aliases-package: com.wyxedu.springcloud.entity # 实例类所在的包,这样通过类名就可以引用
//@EnableDiscoveryClient 引入的是Nacos发现注解
@EnableDiscoveryClient
@SpringBootApplication
public class MemberNacosProviderApplication10004 {
public static void main(String[] args) {
SpringApplication.run(MemberNacosProviderApplication10004.class, args);
System.out.println();
}
}
1. 我们的前端如果是以json格式来发送添加信息Member, 那么我们需要使用@RequestBody, 才能将数据封装到对应的bean, 同时保证http的请求头的 content-type是对应
2. 如果前端是以表单形式提交了,则不需要使用@RequestBody, 才会进行对象参数封装, 同时保证http的请求头的 content-type是对应
@RestController
@Slf4j
public class MemberController {
@Resource
private MemberService memberService;
@PostMapping(value = "/member/save")
public Result save(@RequestBody Member member) {//增加
log.info("会员服务方接收到member= " + member);
int result = memberService.save(member);
log.info("reset= " + result);
if (result > 0) { //成功
return Result.success(" 添加用户成功 member-service-nacos-provider-10004", result);
} else {
return Result.error("401", "添加用户失败");
}
}
//这里使用url占位符+@PathVariable
@GetMapping(value = "/member/get/{id}")
public Result getMemberById(@PathVariable("id") Long id) {
Member member = memberService.queryMemberById(id);
log.info("查询结果= " + member);
if (member != null) {
return Result.success(" 查询成功member-service-nacos-provider-10004",
member);
} else {
return Result.error("402", "ID= " + id + " 不存在");
}
}
}
1 启动Nacos Server 8848
2 启动member-service-nacos-provider-10004
3 观察nacos 服务是否注册成功
浏览器: http://localhost:10004/member/get/1
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druid-spring-boot-starterartifactId>
<version>1.1.17version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
<dependency>
<groupId>com.hspedu.springcloudgroupId>
<artifactId>e_commerce_center-common-apiartifactId>
<version>${project.version}version>
dependency>
dependencies>
server:
port: 10006
spring:
application:
name: member-service-nacos-provider #配置应用的名称
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/e_commerce_center_db?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username: root
password: 自己的密码
#配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #配置Nacos Server的地址
#配置暴露所有的监控点
management:
endpoints:
web:
exposure:
include: '*'
#配置mybatis
mybatis:
mapper-locations: classpath:mapper/*.xml #指定mapper.xml文件位置
type-aliases-package: com.hspedu.springcloud.entity # 实例类所在的包,这样通过类名就可以引用
//@EnableDiscoveryClient 引入的是Nacos发现注解
@EnableDiscoveryClient
@SpringBootApplication
public class MemberNacosProviderApplication10006 {
public static void main(String[] args) {
SpringApplication.run(MemberNacosProviderApplication10006.class,args);
}
}
1. 我们的前端如果是以json格式来发送添加信息Member, 那么我们需要使用@RequestBody, 才能将数据封装到对应的bean, 同时保证http的请求头的 content-type是对应
2. 如果前端是以表单形式提交了,则不需要使用@RequestBody, 才会进行对象参数封装, 同时保证http的请求头的 content-type是对应
@RestController
@Slf4j
public class MemberController {
@Resource
private MemberService memberService;
@PostMapping(value = "/member/save")
public Result save(@RequestBody Member member) {//增加
log.info("会员服务方接收到member= " + member);
int result = memberService.save(member);
log.info("reset= " + result);
if (result > 0) { //成功
return Result.success(" 添加用户成功 member-service-nacos-provider-10004", result);
} else {
return Result.error("401", "添加用户失败");
}
}
//这里使用url占位符+@PathVariable
@GetMapping(value = "/member/get/{id}")
public Result getMemberById(@PathVariable("id") Long id) {
Member member = memberService.queryMemberById(id);
log.info("查询结果= " + member);
if (member != null) {
return Result.success(" 查询成功member-service-nacos-provider-10004",
member);
} else {
return Result.error("402", "ID= " + id + " 不存在");
}
}
}
1 启动Nacos Server 8848
2 启动member-service-nacos-provider-10006
3 观察nacos 服务是否注册成功
浏览器: http://localhost:10006/member/get/1
参考member-service-consumer-80 来创建member-service-nacos-consumer-80 即可修改pom.xml
将member-service-consumer-80 的pom.xml 的… 拷贝过来,修改即可增加这个包
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
server:
port: 80
spring:
application:
name: member-service-nacos-consumer-80
#配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #nacos server的地址
@SpringBootApplication
@EnableDiscoveryClient //引入的是启动 nacos发现注解
@EnableFeignClients
public class MemberNacosConsumerApplication80 {
public static void main(String[] args) {
SpringApplication.run(MemberNacosConsumerApplication80.class,args);
}
}
/**
* CustomizationBean: 配置类
* 配置注入RestTemplate bean/对象
*/
@Configuration
public class CustomizationBean {
//说明: 配置注入RestTemplate bean/对象
//这里的@LoadBalanced 就是赋予 RestTemplate 负载均衡的能力
//默认是使用轮询算法来访问远程调用接口/地址
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
@RestController
@Slf4j
public class MemberNacosConsumerController {
//说明 http://member-service-nacos-provider 就是服务注册到Nacos server的服务名,注意这里是小写
public static final String MEMBER_SERVICE_NACOS_PROVIDER_URL =
"http://member-service-nacos-provider"; //老师分析一下这里?应该这么填写
//配置RestTemplate
@Resource
private RestTemplate restTemplate;
//方法1/接口. 添加member
@PostMapping("/member/nacos/consumer/save")
public Result<Member> save(Member member) {
return restTemplate.postForObject(MEMBER_SERVICE_NACOS_PROVIDER_URL
+ "/member/save", member, Result.class);
}
//方法2/接口, 查询member
@GetMapping("/member/nacos/consumer/get/{id}")
public Result<Member> getMemberById(@PathVariable("id") Long id) {
return restTemplate.getForObject(
MEMBER_SERVICE_NACOS_PROVIDER_URL + "/member/get/" + id, Result.class);
}
}
1 启动Nacos Server 8848
2 启动member-service-nacos-provider-10004/10006
3 启动member-service-nacos-consumer-80
4 浏览器: http://localhost/member/nacos/consumer/get/1
/**
* RibbonRule: 配置类: 配置注入自己的负载均衡算法
*/
@Configuration
public class RibbonRule {
@Bean
public IRule myRibbtonRule() {
//这里返回的是RandomRule, 小伙伴也可以自己指定
return new RandomRule();
}
}
CP: 服务可以不能用,但必须要保证数据的一致性。
AP: 数据可以短暂不一致,但最终是需要一致的,无论如何都要保证服务的可用。
取舍:只能在CP 和AP 选择一个平衡点, 大多数都是选择AP 模式
Nacos 集群默认支持的是CAP原则中的AP原则,但是也可切换为CP原则(一般不切换)
CURL切换命令: curl -X PUT
‘$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP’
URL指令:
$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP
参考: https://www.jianshu.com/p/c56e22c222bb
Data ID: e-commerce-nacos-config-client-dev.yaml
先创建e-commerce-nacos-config-client5000 模块,参考以前的方法
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>com.hspedu.springcloudgroupId>
<artifactId>e_commerce_center-common-apiartifactId>
<version>${project.version}version>
dependency>
dependencies>
spring:
profiles:
active: dev #指定环境,常见的环境有 dev开发/test测试/prod生产
nacos 配置客户端/当前的微服务模块, 会根据配置,找到配置中心的数据(配置文件)
config.server-addr: localhost:8848 可以找到配置中心
spring.application.name 对应是DataId e-commerce-nacos-config
在application.yml: 配置 spring.profiles.active dev
spring.cloud.nacos.config.file-extension 配置文件的扩展名 .yaml
小结: 根据配置 就是 到 localhost:8848 下的 e-commerce-nacos-config-dev.yaml 获取配置信息/数据
规则就是: s p r i n g . a p p l i c a t i o n . n a m e − {spring.application.name}- spring.application.name−{spring.profiles.active}.${spring.cloud.nacos.config.file-extension}来定位配置中心的 Data ID
server:
port: 20000 #端口
spring:
application:
#这里的name需要参考nacos 配置中心的Data Id
name: e-commerce-nacos-config-client
#配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定yaml格式的配置
@SpringBootApplication
@EnableDiscoveryClient
public class NacosConfigClientApplication5000 {
public static void main(String[] args) {
SpringApplication.run(NacosConfigClientApplication5000.class, args);
}
}
@RestController
@Slf4j
@RefreshScope //spring cloud原生注解,实现了配置数据的自动刷新
public class NacosConfigClientController {
/**
* 1. client 会拉取nacos server 的 e-commerce-nacos-config-client-dev.yaml
* config:
* ip: "122.22.22.22"
* name: "大家好"
* 2. @Value("${config.ip}") 会将 config.ip 赋给 configIp
* 3. 这里${config.ip} 不能乱写,要有依据
*/
@Value("${config.ip}")
private String configIp;
@Value("${config.name}")
private String configName;
@GetMapping("/nacos/config/ip")
public String getConfigIp() {
return configIp;
}
@GetMapping("/nacos/config/name")
public String getConfigName() {
return configName;
}
}
1 启动Nacos Server
2 启动e-commerce-nacos-config-client5000
3 浏览器: http://localhost:5000/nacos/config/ip
NacosConfigClientController.java 的@Value(“${config.ip}”), 是import org.springframework.beans.factory.annotation.Value;而不是lombok 包下的.
配置文件application.yml 和bootstrap.yml 结合会得到配置文件/资源的地址
参考文档: https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
注意在Nacos Server 的配置文件的后缀是.yaml , 而不是.yml
在项目初始化时,要保证先从配置中心进行配置拉取,拉取配置之后,才能保证项目的正常启动, 也就是说如果项目不能正确的获取到Nacos Server 的配置数据,项目是启动不了的.
springboot 中配置文件的加载是存在优先级顺序的, bootstrap.yml 优先级高于application.yml
@RefreshScope 是springcloud 原生注解,实现配置信息自动刷新, 如果在Nacos Server 修改了配置数据,Client 端就会得到最新配置[演示]
使用Data ID 方案解决
spring:
profiles:
active: text #指定环境,常见的环境有 dev开发/test测试/prod生产
浏览器输入: http://localhost:5000/nacos/config/ip
spring:
profiles:
active: dev #指定环境,常见的环境有 dev开发/test测试/prod生产
server:
port: 20000 #端口
spring:
application:
#这里的name需要参考nacos 配置中心的Data Id
name: e-commerce-nacos-config-client
#配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定yaml格式的配置
group: search #指定search组,默认是DEFAULT_GROUP
1 浏览器: http://localhost:5000/nacos/config/ip
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e5gC26jp-1685059933336)(<转存失败,建议直接上传图片文件 …/%E5%9B%BE%E7%89%87/image-20230526074910029.png>)]
spring:
profiles:
active: dev #指定环境,常见的环境有 dev开发/test测试/prod生产
增加Namespace 参数
server:
port: 20000 #端口
spring:
application:
#这里的name需要参考nacos 配置中心的Data Id
name: e-commerce-nacos-config-client
#配置nacos
cloud:
nacos:
discovery:
server-addr: localhost:8848 #服务注册中心地址
config:
server-addr: localhost:8848 #配置中心地址
file-extension: yaml #指定yaml格式的配置
group: search #指定search组,默认是DEFAULT_GROUP
namespace: e37564de-2e0a-4f79-96e9-23ac35b90936 #指定对应namespace id[阿里]
浏览器输入: http://localhost:5000/nacos/config/ip
Nacos默认的命名空间是public,Namespace主要用来实现配置隔离, 隔离范围大
Group默认是DEFAULT GROUP,Group可以把不同的微服务划分到同一个分组里面去
Service就是微服务, 相同的Service可以是一个Cluster(簇/集群), Instance 就是微服务的实例