Featured image of post Spring Boot 整合 OpenFeign + Nacos 的坑

Spring Boot 整合 OpenFeign + Nacos 的坑

Nacos先在本地部署 Nacos server,然后在 springBoot 项目中添加依赖,理想情况下,

Nacos

先在本地部署 Nacos server,然后在 springBoot 项目中添加依赖,理想情况下,服务会自动会注册到注册中心。

环境

  • SpringBoot 版本:2.3.1.RELEASE
  • Nacos server 版本:2.0.3
  • nacos-discovery-spring-boot-starter 版本:0.2.10

Nacos Server

之前用过 Nacos 的 V1 版本,V2 版本没用过,这次用最新版本做个试验。

本地部署 Nacos 没什么问题,我的本地环境是 Mac, 下载好最新的版本 (https://github.com/alibaba/nacos/archive/refs/tags/2.0.3.zip) 解压后,到 bin 目录执行

1sh startup.sh -m standalone

然后浏览器查看 http://localhost:8848/nacos/ 用户名密码都是:nacos

Image

可以看到,我用的版本是 2.0.3

Spring Boot

出问题的地方是在程序中引入的时候,由于要演示 feign 的远程调用,我们分别创建两个项目,provier 和 consumer.

首先创建 provider, 先看下 pom.xml 文件中的依赖,可以看到跟 nacos 相关的只有一个。

 1 <!-- BOM 全局管理 starter 版本 -->
 2    <dependencyManagement>
 3        <dependencies>
 4            <dependency>
 5                <groupId>org.springframework.boot</groupId>
 6                <artifactId>spring-boot-dependencies</artifactId>
 7                <version>${spring-boot-dependencies.version}</version>
 8                <scope>import</scope>
 9                <type>pom</type>
10            </dependency>
11        </dependencies>
12    </dependencyManagement>
13
14    <dependencies>
15
16        <!-- openfeign -->
17        <dependency>
18            <groupId>org.springframework.cloud</groupId>
19            <artifactId>spring-cloud-starter-openfeign</artifactId>
20            <version>${spring-cloud-starter-openfeign.version}</version>
21        </dependency>
22
23        <dependency>
24            <groupId>org.projectlombok</groupId>
25            <artifactId>lombok</artifactId>
26            <version>${lombok.version}</version>
27            <scope>provided</scope>
28        </dependency>
29        <dependency>
30            <groupId>org.springframework.boot</groupId>
31            <artifactId>spring-boot-starter</artifactId>
32        </dependency>
33        <dependency>
34            <groupId>org.springframework.boot</groupId>
35            <artifactId>spring-boot-starter-test</artifactId>
36            <scope>test</scope>
37        </dependency>
38
39        <dependency>
40            <groupId>org.springframework.boot</groupId>
41            <artifactId>spring-boot-starter-web</artifactId>
42        </dependency>
43
44        <dependency>
45            <groupId>com.alibaba.boot</groupId>
46            <artifactId>nacos-discovery-spring-boot-starter</artifactId>
47            <version>0.2.10</version>
48        </dependency>
49
50        <dependency>
51            <groupId>com.google.guava</groupId>
52            <artifactId>guava</artifactId>
53            <version>30.1.1-jre</version>
54        </dependency>
55    </dependencies>

然后再看下 application.yml

 1server:
 2  port: 8080
 3  servlet:
 4    context-path: /provider
 5spring:
 6  mvc:
 7    throw-exception-if-no-handler-found: true # 处理 404 问题
 8  resources:
 9    add-mappings: false # 关闭 404 资源映射
10  application:
11    name: feign-provider
12
13nacos:
14  discovery:
15    server-addr: 127.0.0.1:8848 # Nacos 服务器地址
16   

通过官方文档查看,配置比较简单,没什么特殊的。这里强调下,不需要在入口程序 BootstrapApplication 添加什么注解

然后就出问题了,服务死活注册不上去,服务列表一直是空的。

翻阅了各种文档和配置,终于在 github 的 wiki 上找到了官方的说明:https://github.com/nacos-group/nacos-spring-boot-project/wiki

Image

我需要的就是这个:

1# 是否允许服务自动注册(默认为关闭自动注册)
2nacos.discovery.auto-register=true

由于之前用的是 V1 的版本,2 以后的配置没接触过,看来想要自动注册要把这个从 0.2.3 才有的配置加上(我们试验用的 starter 版本是 0.2.10)

以后跟 nacos-discovery-spring-boot-starter 相关版本配置有关的功能,可以参考官方的 wiki:

Image

加上这个配置又丰富了一下后,配置文件变成这样:

 1server:
 2  port: 8080
 3  servlet:
 4    context-path: /provider
 5
 6spring:
 7  mvc:
 8    throw-exception-if-no-handler-found: true # 处理 404 问题
 9  resources:
10    add-mappings: false # 关闭 404 资源映射
11  application:
12    name: feign-provider
13
14nacos:
15  discovery:
16    server-addr: 127.0.0.1:8848 # Nacos 服务器地址
17    auto-register: true # 是否自动注册到 Nacos 中。默认为 false。
18    namespace:  # 使用的 Nacos 的命名空间,默认为 null。
19    register:
20      service-name: ${spring.application.name} # 注册到 Nacos 的服务名
21      group-name: DEFAULT_GROUP # 使用的 Nacos 服务分组,默认为 DEFAULT_GROUP。
22    

然后就顺利地注册上了:

Image

but

正当我兴冲冲地去写完 consumer 准备消费的时候,却发现怎么也消费不了,google 了个遍,一直都报这个错:

Load balancer does not have available server for client

实在是不想 debug 源码了,消耗完耐心后,决定不用 springBoot 去整合了,还是回到

Spring Cloud + Spring Cloud Alibaba 的路上。

Spring Cloud + Spring Cloud Alibaba

首先要弄清楚版本间的依赖关系,因为版本众多,稍不注意就容易出问题,可以参考这里:

https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

而 Nacos 的例子,官方有一个直接抄 https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/zh-cn/index.html#%E4%B8%80%E4%B8%AA%E4%BD%BF%E7%94%A8_nacos_discovery%E8%BF%9B%E8%A1%8C%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E5%8F%91%E7%8E%B0%E5%B9%B6%E8%B0%83%E7%94%A8%E7%9A%84%E4%BE%8B%E5%AD%90

参考完官方的例子后,我的 provider 的 pom.xml 修改如下:

 1    <parent>
 2        <groupId>org.springframework.boot</groupId>
 3        <artifactId>spring-boot-starter-parent</artifactId>
 4        <version>2.3.2.RELEASE</version>
 5        <relativePath/>
 6    </parent>
 7
 8    <properties>
 9        <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
10        <maven-source.version>3.2.1</maven-source.version>
11        <lombok.version>1.18.12</lombok.version>
12
13        <spring.boot.version>2.3.2.RELEASE</spring.boot.version>
14        <spring.cloud.version>Hoxton.SR9</spring.cloud.version>
15        <spring.cloud.alibaba.version>2.2.6.RELEASE</spring.cloud.alibaba.version>
16
17    </properties>
18
19    <dependencyManagement>
20        <dependencies>
21            <dependency>
22                <groupId>org.springframework.cloud</groupId>
23                <artifactId>spring-cloud-dependencies</artifactId>
24                <version>${spring.cloud.version}</version>
25                <type>pom</type>
26                <scope>import</scope>
27            </dependency>
28            <dependency>
29                <groupId>com.alibaba.cloud</groupId>
30                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
31                <version>${spring.cloud.alibaba.version}</version>
32                <type>pom</type>
33                <scope>import</scope>
34            </dependency>
35        </dependencies>
36    </dependencyManagement>
37
38    <dependencies>
39        <dependency>
40            <groupId>org.springframework.boot</groupId>
41            <artifactId>spring-boot-starter-web</artifactId>
42        </dependency>
43
44        <dependency>
45            <groupId>org.springframework.cloud</groupId>
46            <artifactId>spring-cloud-starter-openfeign</artifactId>
47        </dependency>
48
49        <dependency>
50            <groupId>org.springframework.boot</groupId>
51            <artifactId>spring-boot-starter-actuator</artifactId>
52        </dependency>
53
54        <dependency>
55            <groupId>com.alibaba.cloud</groupId>
56            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
57        </dependency>
58    </dependencies>

application.yml 修改如下:

 1server:
 2  port: 8080
 3  servlet:
 4    context-path: /provider
 5
 6spring:
 7  mvc:
 8    throw-exception-if-no-handler-found: true # 处理 404 问题
 9  resources:
10    add-mappings: false # 关闭 404 资源映射
11  application:
12    name: feign-provider
13
14  cloud:
15    nacos:
16      discovery:
17        server-addr: 127.0.0.1:8848 # Nacos 服务器地址
18        # namespace: 03afd923-0972-48c4-80fc-69098625d8b0

controller 的接口该怎么写还怎么写,在启动类需要加入一个注解

1@EnableDiscoveryClient

之后把 provider 启动起来,到 nacos 的 dashboard 看一下注册成功了。

接着是 consumer

consumer 的 pom.xml、application.yml 与 provider 一样入口程序同样要加入:

1@EnableDiscoveryClient

feign 接口:

1@FeignClient(name = "feign-provider",path = "/provider")
2public interface ProviderClient {
3
4    @GetMapping("test/hello")
5    String sayHello();
6
7}

controller 消费一下:

 1@RestController
 2@RequestMapping("/test")
 3public class ConsumerController {
 4
 5    @Autowired
 6    private ProviderClient remoteClient;
 7
 8    @GetMapping("/consume")
 9    public String consume() {
10
11        // ServiceInstance serviceInstance = loadBalancerClient.choose("feign-provider");
12        // String url = String.format("http://%s:%s/echo/%s",serviceInstance.getHost(),serviceInstance.getPort(),"feign-provider");
13        // return restTemplate.getForObject(url,String.class);
14
15        return remoteClient.sayHello();
16    }
17
18}

用浏览器请求 consumer 接口测试成功,可以调用到远程 provider 服务。

总结

整体看技术上没什么难度,但 nacos-spring-boot-projec 这个项目直觉上是有坑的,试了许久还是有问题,也许是我没找到问题的根源,所以如果你有耐心可以试着搞搞,如果着急用,还是 Spring Cloud Alibaba 靠谱。

参考

位旅人路过 次翻阅 初次见面