文章目录
- 前言
- 6 Nacos配置管理
- 6.1 在Nacos中添加配置文件
- 6.2 微服务拉取配置
- 6.3 配置热更新
- 6.3.1 方式一:`@RefreshScope`注解
- 6.3.2 方式二:`@ConfigurationProperties`注解
- 6.4 配置共享
- 6.4.1 添加一个环境共享配置
- 6.4.2 实现读取共享配置
- 6.5 配置共享的优先级
- 7 Feign远程调用
- 7.1 使用Feign替代RestTemplate
- 7.2 自定义配置
- 7.2.1 配置文件方式
- 7.2.2 Java代码方式
前言
SpringCloud学习笔记系列文章:
SpringCloud学习笔记(一)微服务介绍、服务拆分和RestTemplate远程调用、Eureka注册中心
SpringCloud学习笔记(二)Ribbon负载均衡、Nacos注册中心、Nacos与Eureka的区别
6 Nacos配置管理
Nacos除了可以做注册中心,还可以做配置管理。
当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会变得非常麻烦,而且很容易出错。因此,这就需要一个统一配置管理方案,可以集中管理所有实例的配置。
Nacos一方面可以将配置集中管理,另一方面可以在配置变更时,及时通知微服务,实现配置的热更新。如图:
6.1 在Nacos中添加配置文件
在Nacos管理页面,进入“配置管理”-“配置列表”页面,点击“创建配置”:
在“新建配置”页面填写配置信息:
填写完成后点击“发布”,即可新增一条配置:
要注意的是,一般是需要热更新的配置才有放到Nacos管理的必要,基本不会变更的配置还是保存在微服务本地比较好。
6.2 微服务拉取配置
微服务要拉取Nacos中管理的配置文件,并且与本地的application.yml配置文件合并,才能完成项目启动。但Nacos地址是配置在本地的application.yml文件中的,启动前服务尚未读取本地的application.yml,又如何得知Nacos地址呢?
为此,Spring引入了一种新的配置文件:bootstrap.yaml文件。它会在application.yml之前被读取,其流程如下:
- 1)引入nacos-config依赖
在user-service工程中,引入nacos-config依赖:
<!--sc_demo\user-service\pom.xml--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
- 2)添加bootstrap.yaml
在user-service工程的resources目录下,添加bootstrap.yaml文件,其内容如下:
# sc_demo\user-service\src\main\resources\bootstrap.yamlspring:application:# 服务名称name: user-serviceprofiles:#开发环境active: devcloud:nacos:# Nacos地址server-addr: localhost:8848 config:# 文件后缀名file-extension: yaml
通过该配置,可以根据spring.cloud.nacos.server-addr
获取Nacos地址,再根据${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
作为文件id,去Nacos读取配置。在本例中,就是去读取user-service-dev.yaml
。
- 3)读取Nacos配置
下面在UserController类中编写一个测试方法来读取Nacos配置:
// com.star.user.web.UserController@Value("${dir.upload}")
private String uploadDir;@GetMapping("/now")
public String now() {System.out.println("读取Nacos配置:dir.upload = " + uploadDir);return uploadDir;
}
调用http://127.0.0.1:8081/user/now
接口,控制台打印信息如下:
读取Nacos配置:dir.upload = /usr/local/upload
可见,Nacos中的配置已被成功读取。
6.3 配置热更新
使用Nacos管理配置文件的目的,是修改Nacos中的配置后,微服务中无需重启即可让配置生效,也就是配置热更新。
要实现配置热更新,有两种方式:
6.3.1 方式一:@RefreshScope
注解
在使用@Value
注解注入变量的类上添加@RefreshScope
注解,例如UserController类:
// com.star.user.web.UserController@Slf4j
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {@Value("${dir.upload}")private String uploadDir;// ...
}
重启user-service(8081)服务后,修改Nacos中的配置:
再次调用http://127.0.0.1:8081/user/now
接口,控制台打印信息如下:
可见,user-service(8081)服务发现了配置的修改,并自动更新。
6.3.2 方式二:@ConfigurationProperties
注解
在user-service工程中,添加一个ConfigProperties配置类用于读取配置:
// com.star.user.config.ConfigProperties@Component
@Data
@ConfigurationProperties(prefix = "dir")
public class ConfigProperties {private String upload;
}
然后在UserController类中直接注入ConfigProperties类,以替代@Value
注解:
// com.star.user.web.UserController// @Value("${dir.upload}")
// private String uploadDir;@Autowired
private ConfigProperties configProperties;@GetMapping("/now")
public String now() {// System.out.println("读取Nacos配置:dir.upload = " + uploadDir);// return uploadDir;System.out.println("通过ConfigProperties读取Nacos配置:dir.upload = " + configProperties.getUpload());return configProperties.getUpload();
}
重启user-service(8081)服务后,修改Nacos中的配置:
user-service(8081)服务检测到了配置的修改,在控制台打印修改信息:
再次调用http://127.0.0.1:8081/user/now
接口,控制台打印信息如下:
可见,user-service(8081)服务发现了配置的修改,并自动更新。
6.4 配置共享
微服务在启动时,会去Nacos读取多个配置文件,包括:
[spring.application.name]-[spring.profiles.active].yaml
,例如:user-service-dev.yaml[spring.application.name].yaml
,例如:user-service.yaml
第一种即上文读取的配置文件,而第二种[spring.application.name].yaml
不包含环境信息,因此可以被多个环境共享。
6.4.1 添加一个环境共享配置
6.4.2 实现读取共享配置
在user-service工程中,修改ConfigProperties类,添加要读取的共享属性:
// com.star.user.config.ConfigProperties@Component
@Data
@ConfigurationProperties(prefix = "dir")
public class ConfigProperties {private String upload;private String envSharedValue;
}
修改UserController类,添加一个读取共享属性方法:
// com.star.user.web.UserController@Autowired
private ConfigProperties configProperties;@GetMapping("/share")
public ConfigProperties share() {return configProperties;
}
配置user-service(8081)服务的profile为dev,user-service(8082)服务的profile为test,启动这两个服务:
调用http://127.0.0.1:8081/user/share
接口,返回结果如下:
再调用http://127.0.0.1:8082/user/share
接口,返回结果如下:
可见,不同的服务实例都读取到了user-service.yaml文件的配置,但只有配置了profile为dev的实例才能读取user-service-dev.yaml文件的配置。
6.5 配置共享的优先级
当Nacos、服务本地同时出现相同配置属性时,优先级有高低之分,如图:
7 Feign远程调用
目前,项目中是利用RestTemplate发起远程调用,但这种编码方式存在一些问题:
- 存在硬编码,代码可读性差
- 参数复杂时,URL难以维护
为了解决以上问题,推荐使用Feign来代替RestTemplate,更加优雅地实现http请求的发送。
Feign是一个声明式的http客户端,官网地址:https://github.com/OpenFeign/feign
7.1 使用Feign替代RestTemplate
- 1)引入Feign依赖
在order-service工程的pom.xml文件中引入Feign依赖:
<!--sc_demo\order-service\pom.xml--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 2)添加
@EnableFeignClients
注解
在order-service工程的启动类OrderApplication中添加@EnableFeignClients
注解,开启Feign功能:
// com.star.order.ShopApplication@EnableFeignClients
@MapperScan("com.star.order.mapper")
@SpringBootApplication
public class OrderApplication {...
}
- 3)编写并使用Feign客户端
在order-service中新建一个接口,标注@FeignClient
注解,表示该接口是一个Feign客户端,其完整内容如下:
// com.star.shop.feign.UserClient@FeignClient("user-service")
public interface UserClient {@GetMapping("/user/{id}")User findById(@PathVariable Long id);
}
Feign客户端主要是基于SpringMVC的注解来声明远程调用的信息,如上例中:
- 服务名称:user-service,从Nacos中获取具体的ip和端口
- 请求方式:GET
- 请求路径:/user/{id}
- 请求参数:Long id
- 返回值类型:User
然后修改OrderService类的queryOrderById()
方法,使用Feign客户端来发起http请求:
// com.star.order.service.OrderService@Autowired
private UserClient userClient;public Order queryOrderById(Long orderId) {// 1.查询订单Order order = orderMapper.findById(orderId);// 2.远程查询用户信息// String url = "http://127.0.0.1:8081/user/" + order.getUserId();// 2.1 使用服务名代替ip和端口// String url = "http://user-service/user/" + order.getUserId();// User user = restTemplate.getForObject(url, User.class);// 2.2 使用Feign客户端来发起http请求User user = userClient.findById(order.getUserId());order.setUser(user);// 3.返回return order;
}
- 4)功能测试
重启order-service(8080)服务,调用http://127.0.0.1:8080/order/101
接口:
可见,用户信息被成功查询,Feign客户端正常工作。
7.2 自定义配置
Feign支持很多自定义配置,如下表所示:
类型 | 作用 | 说明 |
---|---|---|
feign.Logger.Level | 修改日志级别 | 包含四种不同的级别:NONE、BASIC、HEADERS、FULL |
feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 |
feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 |
feign. Contract | 支持的注解格式 | 默认是SpringMVC的注解 |
feign. Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 |
一般情况下,默认值就能满足使用。如果需要自定义,只需要通过配置文件继续配置或创建自定义的@Bean覆盖默认Bean即可。
下面以修改日志级别为例来说明如何使用自定义配置:
7.2.1 配置文件方式
基于配置文件修改Feign日志级别可以针对单个服务,也可以针对所有服务::
# sc_demo\order-service\src\main\resources\application.ymlfeign:client:config:user-service: # 针对单个微服务的配置,填写 服务名# default: # 针对所有微服务的配置,填写 defaultloggerLevel: FULL # 日志级别
Feign日志级别分为四种:
- NONE:不记录任何日志信息,这是默认值。
- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间。
- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息。
- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
重启order-service(8080)服务,调用http://127.0.0.1:8080/order/101
接口,控制台打印Feign调用http请求的信息:
7.2.2 Java代码方式
先注释掉上面配置文件中的Feign日志级别配置,然后在order-service工程中新建一个配置类:
// com.star.order.feign.DefaultFeignConfiguration@Configuration
public class DefaultFeignConfiguration {@Beanpublic Logger.Level feignLogLevel() {// 日志级别为BASICreturn Logger.Level.BASIC;}
}
如果要全局生效,则将该类配置到启动类的@EnableFeignClients
注解中:
// com.star.order.OrderApplication@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
@MapperScan("com.star.order.mapper")
@SpringBootApplication
public class OrderApplication {...
}
如果要局部生效,则将该类配置到对应Feign客户端的@FeignClient
注解中:
// com.star.order.feign.UserClient@FeignClient(value = "user-service", configuration = DefaultFeignConfiguration.class)
public interface UserClient {...
}
重启order-service(8080)服务,调用http://127.0.0.1:8080/order/101
接口,控制台打印Feign调用http请求的信息:
可见,日志只记录了请求的方法、URL以及响应状态码和执行时间等,符合BASIC日志级别。
…
本节完,更多内容请查阅分类专栏:SpringCloud学习笔记
本文涉及代码下载地址:https://gitee.com/weidag/springcloud_learning.git
感兴趣的读者还可以查阅我的另外几个专栏:
- SpringBoot源码解读与原理分析(已完结)
- MyBatis3源码深度解析(已完结)
- Redis从入门到精通(已完结)
- MyBatisPlus详解(已完结)
- 再探Java为面试赋能(持续更新中…)