# spring-cloud-nacos
**Repository Path**: shang2-8-5/spring-cloud-nacos
## Basic Information
- **Project Name**: spring-cloud-nacos
- **Description**: springCloud+nacos整合
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2023-10-12
- **Last Updated**: 2023-11-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# spring-cloud-nacos
## 父依赖
```xml
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.2.5.RELEASE
pom
import
```
## 子模块依赖
```xml
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
```
## yml 配置
```yml
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务地址
```
# Nacos 服务分级存储模型
* 一级是服务: 例如userserver
* 二级是集群: 例如:上海,杭州
* 三级是实例,例如杭州机房的某台部署了userserver的服务器
## 服务跨集群调用问题:
服务调用尽可能选择本地集群的服务,跨集群调用延迟较高本地集群不可访问时,再去访问其他集群
## 服务集群属性
修改application.yml添加以下内容
```yml
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务地址
discovery:
cluster-name: HZ # 配置集群名称,也就是机房位置
```
将order-server中设置负载均衡的IRule为NacosRule,这个规则优先会寻找与自己同集群的服务
```yml
userserver:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
```
## 根据权重负载均衡
实际部署中会出现这样的场景:
* 服务器设备性能有差异,部分实例所在及其性能较好,另一些较差,我们希望性能好的机器承担更多的用户请求
Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高权重(0~1之间)

## 环境隔离 - namespace
Nacos中服务存储和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离

修改order-server的application.yml,添加namespace:
```yml
spring:
cloud:
nacos:
server-addr: localhost:8848 # nacos服务地址
discovery:
cluster-name: HZ # 配置集群名称,也就是机房位置
namespace: # 填写命名空间: 填ID
```
*不同namespace下的服务不可见*
## Nacos与Eureka对比
1. Nacos与Eureka的共同点
* 都支持服务注册和服务拉取
* 都支持服务提供者心跳方式做健康检测
2. Nacos与Eureka的区别
* Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
* 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
* Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
* Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式,Eureka采用AP方式
# Nacos 统一配置管理

配置获取步骤

1. 引入Nacos的配置管理客户端依赖(导入到需要在nacos配置的模块)
```xml
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
org.springframework.cloud
spring-cloud-starter-bootstrap
3.0.1
```
2. 在微服务中添加bootstrap.yml配置文件,配置nacos地址,当前环境,服务名称,文件名和后缀。这些决定了程序启动时去nacos读取哪个文件
```yml
spring:
application:
name: userserver
profiles:
active: dev # 环境
cloud:
nacos:
server-addr: localhost:8848 # Nacos地址
config:
file-extension: yaml # 文件后缀名
```
## 配置自动更新
1. 在相关类上添加注解
@RefreshScope
2. 使用@ConfigurationProperties注解
```java
@Component
@Data
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties{
private String dateformat;
}
```
## 多环境配置共享
多种配置的优先级:
服务名-profile.yaml -> 服务名.yaml > 本地配置
当前环境配置 优先级高于 nacos中的配置 优先级高于 本地配置
## 集群搭建步骤:
1. 搭建MySQL集群并初始化数据库表
2. 下载解压nacos
3. 修改集群配置(节点信息),数据库配置
4. 分别启动多个nacos节点
5. nginx反向代理
# Feign 使用步骤
1. 引入依赖
```xml
org.springframework.cloud
spring-cloud-starter-openfeign
```
2. 在项目启动类中添加@EnableFeignClients注解
3. 编写FeignClient接口
```java
@FeignClient("userserver")
public interface UserClients {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
```
4. 使用FeignClient中定义的方法代替RestTemplate
```java
public Order queryOrderById(Long orderId){
Order order = orderMapper.findById(orderId);
// 用feign远程调用
User user = userClients.findById(order.getUserId());
order.setUser(user);
return order;
}
```
## Feign的自定义配置

### 配置Feign日志有两种方式
方式一:配置文件方式
1. 全局生效
```yaml
# Feign日志配置
feign:
client:
config:
default:
loggerLevel: FULL
```
方式二:代码方式先声明一个Bean
```java
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
// 1. 而后如果是全局配置,则把他放到@EnableFeignClients注解中
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
// 2. 如果是局部配置,则把他放到@FeignClient注解中
@FeignClient(value = "userserver", configuration = FeignClientConfiguration.class)
```
## Feign的性能优化
Feign底层的客户端实现
* URLConnection:默认实现,不支持连接池
* Apache HttpClient:支持连接池
* OKHttp:支持连接池
因此优化Feign的性能主要包括:
1. 使用连接池代替默认的URLConnection
2. 日志级别,最好用basic或none
### Feign 添加HttpClient的支持
引入依赖
```xml
io.github.openfeign
feign-httpclient
```
配置文件
```yaml
# 开启httpClient配置
httpclient:
enabled: true #支持httpClient开关
max-connections: 200 # 最大连接数
max-connections-per-route: 50 # 单个路径的最大连接数
```
Feign的优化:
* 日志级别尽量用basic
* 使用HttpClient或者OKHttp代替URLConnection
* * 引入feign-httpClient依赖
* * 配置文件开启httpClient功能,设置连接池参数
## Feign的最佳实践

spring官方不推荐使用

### 实现方式二--- 抽取FeignClient--->feign-api模块
实现最佳实践方式二的步骤如下:
1.首先创建一个module,命名为feign-api,然后引入feign的starter依赖
2.将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中
3.在order-service中引入feign-api的依赖
4.修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包
5.重启测试

推荐第二种
# 统一网关Gateway
网关功能:
* 身份认证和权限校验
* 服务路由,负载均衡
* 请求限流

## 搭建网关步骤
1. 创建新的module,引入SpringCloudGateway依赖和Nacos的服务发现依赖
```xml
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
org.springframework.cloud
spring-cloud-starter-gateway
```
2. 编写路由配置及其nacos地址
```yaml
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名
cloud:
nacos:
server-addr: localhost:8848 # nacos地址
# gateway配置
gateway:
routes: # 网关路由配置
- id: user-server # 路由id,自定义主要是唯一即可
# uri: http://127.0.0.1:8081 # 路由的目标地址 固定地址
uri: lb://userserver # 路由的目标地址 lb就是负载均衡,后面跟服务名称
predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
- Path=/user/** # 这个是按照路径匹配, 只要以/user/开头就符合要求
- id: order-server
uri: lb://orderserver
predicates:
- Path=/order/**
```

## 路由断言工厂
* After:在指定的时间后进行路由 例如
```yaml
predicates:
- After=2021-01-01T11:37:34.485+08:00[Asia/Shanghai]
```
* Before:在指定的时间进行路由 例如:
```yaml
predicates:
- Before=2021-01-01T11:37:34.485+08:00[Asia/Shanghai]
```
* Between:在指定的两个时间之间进行路由 例如:
```yaml
predicates:
- Between=2021-01-01T11:37:34.485+08:00[Asia/Shanghai], 2021-01-07T11:37:34.485+08:00[Asia/Shanghai]
```
* Cookie:cookie匹配 例如:
```yaml
predicates:
- Cookie=username, zhangsan
```
* Header:请求头匹配 例如:
```yaml
predicates:
- Header=X-Request-Id, \d+
```
* Host:请求主机地址 例如:
```yaml
predicates:
- Host=**.abc.org, **.xyz.org
```
* Method:请求方式 例如:
```yaml
predicates:
- Method=GET
```
* Path:请求路径 例如:
```yaml
predicates:
- Path=/foo/{segment}
```
* Query:请求参数 例如:
```yaml
predicates:
- Query=myParam, \d+
```
* RemoteAddr:IP地址 例如:
```yaml
predicates:
- RemoteAddr=192.168.1.1/24
```
* Weight:路由权重处理 例如:
```yaml
predicates:
- Weight=group1, 5
- Weight=group2, 10
```
## 路由过滤器 GatewayFilter

给所有进入userserver的请求加一个请求头
```yaml
// 实现方法
## 添加过滤
# filters:
# - AddRequestHeader=Truth, XYZ
- id: order-server
uri: lb://orderserver
predicates:
- Path=/order/**
# 全局过滤配置
default-filters:
- AddRequestHeader=Truth,ABC
```
过滤器的作用是什么?
对路由的请求或响应做加工处理,比如添加请求头配置在路由下的过滤器只对当前路由的请求生效
defaultFilters的作用是什么?
对所有路由生效的过滤器,比如添加请求头配置在defaultFilters下过滤器对所有路由的请求都生效
### 全局过滤器GlobalFilter

```java
@Component
//@Order(-1) // 优先级
public class AuthorizeFilter implements GlobalFilter, Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap params = request.getQueryParams();
// 2. 获取参数中的authorization 参数
String auth = params.getFirst("authorization");
// 3. 判断参数值是否等于 admin
if ("admin".equals(auth)){
// 4. 是 放行
return chain.filter(exchange);
}
exchange.getResponse().setRawStatusCode(401);
// 5. 否拦截
return exchange.getResponse().setComplete();
}
// 优先级
@Override
public int getOrder() {
return -1;
}
}
```
全局过滤器的作用是什么?对所有路由都生效的过滤器,并且可以自定义处理逻辑
实现全局过滤器的步骤?
* 实现GlobalFilter接口
* 添加@Order注解或实现Ordered接口
* 编写处理逻辑
### 过滤器的执行顺序

### 跨域问题处理
```yaml
spring:
cloud:
gateway:
globalcors:
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
# - "http://localhost:8080"
- "*"
allowedMethods: # 允许的跨域的ajax的请求方式
- "GET"
- "POST"
- "PUT"
- "DELETE"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
exposedHeaders: true # 是否允许请求中携带cookie
maxAge: 36000 # 这次跨域检测的有效期
```