SpringCloud学习笔记(三)Nacos配置管理与热更新、Feign远程调用替代RestTemplate

前言

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.yaml

spring:
  application:
    # 服务名称
    name: user-service
  profiles:
    #开发环境
    active: dev
  cloud:
    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.yml

feign:
  client:
    config:
      user-service: # 针对单个微服务的配置,填写 服务名
      # default: # 针对所有微服务的配置,填写 default
        loggerLevel: 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 {
    @Bean
    public Logger.Level feignLogLevel() {
        // 日志级别为BASIC
        return 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

感兴趣的读者还可以查阅我的另外几个专栏:

  • 16
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
在Spring Cloud微服务架构中,Nacos是一个注册中心和配置中心。Feign是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加容易。 使用Feign调用接口需要以下步骤: 1. 在pom.xml中添加Feign依赖 ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> ``` 2. 在启动类上添加@EnableFeignClients注解启用Feign客户端 ```java @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 3. 创建接口,并使用@FeignClient注解指定调用的服务名称和服务路径 ```java @FeignClient(name = "service-provider") public interface UserService { @GetMapping("/user/{id}") String getUserById(@PathVariable("id") Long id); } ``` 其中,name属性指定服务名称,GetMapping注解指定服务路径。 4. 在需要使用该服务的地方注入UserService并调用方法即可 ```java @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/user/{id}") public String getUserById(@PathVariable("id") Long id) { return userService.getUserById(id); } } ``` 在这个例子中,我们定义了一个名为UserService的Feign客户端,指定了调用的服务名称和服务路径。然后在UserController中注入了UserService并调用了其方法。最终,Feign会自动将该请求转发到名为service-provider的微服务,并返回结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰色孤星A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值