目标及软件版本
目标
- dubbo和spring共同使用nacos为注册中心
- springboot、springcloud、dubbo、nacos都为比较新的版本
环境及版本要求:
- jdk版本:17,
使用jdk17的原因是springboot3必须使用jdk17
- springcloud版本:2022.0.2,
IDEA中能够使用到的最新springboot的spring-cloud-dependencies版本
- sprinbcloud-alibaba版本:2022.0.0.0-RC1,
阿里提供的最新的spring-cloud-alibaba-dependencies版本
- apache dubbo版本:3.2.0-beta.6,
apache提供的最新的dubbo-bom版本
- springboot版本:3.0.5,
IDEA中能够使用到的最新spring-boot-dependencies版本
- nacos版本:2.2.1,
阿里提供最新的nacos服务版本
所谓最新
也只不过是截止到当前日期:2023-04-02 18:12
开始整事儿
搭建nacos服务
- 阿里官方nacos的安装和下载在这里:https://nacos.io/zh-cn/docs/quick-start.html,需要自行选择naocs版本为2.2.1进行安装
- nacos将使用数据库方式,在本示例中使用的数据库为
MySql
,版本为8.0.31-0ubuntu0.22.04.1
- nacos开启鉴权访问,配置文件
nacos/conf/application.properties
中修改的地方如下:
# 数据库连接配置,原来这三项是注释了的,去掉前面的"#"号
# 数据库连接地址及数据库名称根据自己实际情况修改
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
# 数据库的用户名及密码根据自己的实际情况修改
db.user.0=root
db.password.0=rootPassword
# 原来该配置的为false,开启nacos接入鉴权,这行最为关键
nacos.core.auth.enabled=true
# 当nacos.core.auth.enabled设置为true之后,下面两项必须给值,原来的以下两项都没有值,可以直接使用下面的值,不报错
nacos.core.auth.server.identity.key=serverIdentity
nacos.core.auth.server.identity.value=security
# 原来这项配置为空,key还必须为base64,就用以下这个key可以不报错
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
- 以上就是Nacos服务的配置需要修改的地方了,其他的配置暂时保持不变
IDEA创建父工程springboot-dubo-feign-nacos-demo
- 父工程的pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cyp</groupId>
<artifactId>springboot-dubo-feign-nacos-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<name>springboot-dubo-feign-nacos-demo</name>
<description>springboot-dubo-feign-nacos-demo</description>
<packaging>pom</packaging>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>3.0.5</spring-boot.version>
<spring-cloud.version>2022.0.2</spring-cloud.version>
<spring-cloud-alibaba.version>2022.0.0.0-RC1</spring-cloud-alibaba.version>
<dubbo.version>3.2.0-beta.6</dubbo.version>
</properties>
<modules>
<module>springboot-dubbo-feign-nacos-interface</module>
<module>springboot-dubbo-feign-nacos-producer</module>
<module>springboot-dubbo-feign-nacos-consumer</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- nacos配置中心 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 额外的工具 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.11</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<!-- spring cloud 及 spring boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- nacos alibaba cloud -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- apache dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
-
父工程中不需要有自己的任何目录及代码,里面用来放它的子工程就好,如下图所示
image.png
创建接口模块工程springboot-dubbo-feign-nacos-interface
- 该模块中只定义dubbo暴露的接口和用于对比性能的openfeign的FeignClient注释的接口
- 接口模块的pom.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.cyp</groupId>
<artifactId>springboot-dubo-feign-nacos-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>springboot-dubbo-feign-nacos-interface</artifactId>
<version>1.0</version>
<name>springboot-dubbo-feign-nacos-interface</name>
<description>springboot-dubbo-feign-nacos-interface</description>
<packaging>jar</packaging>
</project>
-
创建几个目录,一个目录用于存放dubbo的接口,一个用于存放openfeign的接口,一个用于存放接口传递的公共Pojo,目录结构如下图所示:
image.png - IEchoDubbo内容如下:
public interface IEchoDubbo {
R<EchoDTO> echo(R<EchoDTO> dto);
}
- IEchoFeign内容如下:
@FeignClient(name = "producer-server", contextId = "IEchoFeign", fallback = IEchoFeignFallback.class)
public interface IEchoFeign {
@PostMapping("/producer/echo/get")
R<EchoDTO> echo(@RequestBody R<EchoDTO> dto);
}
- IEchoFeignFallback内容如下:
@Component
public class IEchoFeignFallback implements IEchoFeign {
@Override
public R<EchoDTO> echo(R<EchoDTO> dto) {
return new R<>();
}
}
- R内容如下:
@Data
public class R<T> implements Serializable {
private Integer code;
private String msg;
private T data;
}
- EchoDTO内容如下:
@Data
public class EchoDTO implements Serializable {
private String name;
private Map<String, String> map;
}
创建服务提供模块springboot-dubbo-feign-nacos-producer
- 该模块中提供服务实现,实质就是对模块
springboot-dubbo-feign-nacos-interface
中的接口进行具体的实现,目录结构如下图所示:
image.png - 该模块中的pom.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.cyp</groupId>
<artifactId>springboot-dubo-feign-nacos-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>springboot-dubbo-feign-nacos-producer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-dubbo-feign-nacos-producer</name>
<description>springboot-dubbo-feign-nacos-producer</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.cyp</groupId>
<artifactId>springboot-dubbo-feign-nacos-interface</artifactId>
<version>1.0</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- 以下两个引用是把dubbo的注册中心由它原生的zookeeper改为nacos的关键引用 -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!-- 按照官方的说法,要么引用上面的nacos-client和dubbo,要么引用下面dubbo-registry-nacos -->
<!-- 但是当我使用下面的引用,去掉上面的引用,项目也能启动,但是在启动的过程中,会提示有些类存在于多个地方 -->
<!-- 但是当我使用上面的两个引用(也是官方给的示例), 项目正常启动且不会报错 -->
<!-- Introduce Dubbo Nacos extension, or you can add Nacos dependency directly as shown above 这段话是官方的原注释 -->
<!--
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>
-->
</dependencies>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 该模块的bootstrap.yml配置内容如下:
server:
port: 8081
spring:
application:
name: producer-server
profiles:
active: test
cloud:
nacos:
username: nacos
password: nacos
# 照抄的朋友们,请将127.0.0.1及8848改为你们的nacos配置的地址和端口
server-addr: 127.0.0.1:8848
config:
# 照抄的朋友们,请将以下配置改为你们nacos中对应的配置
group: DEFAULT_GROUP
prefix: application
file-extension: yaml
namespace: 4977df2a-9d19-4060-b82f-4d695704e165
dubbo:
application:
# 此处没有延用spring.application.name是因为当前项目本身也会注册到nacos中,如果dubbo也延用相同的名称,在nacos服务里会看到注册的producer-server服务数为2
# 我个人认为这会造成服务混乱,毕竟一个是该服务本身,一个是dubbo相互调用要使用的注册
# 如果我的理解是错误的,希望朋友们在评论中给予指定,目前这样配置之后,会在nacos中看到该服务注册了两个,一个是producer-server,另一个是producer-dubbo-server
name: producer-dubbo-server
protocol:
name: dubbo
port: -1
registry:
# 配置dubbo的注册中心为nacos
address: nacos://${spring.cloud.nacos.server-addr}
username: ${spring.cloud.nacos.username}
password: ${spring.cloud.nacos.password}
group: ${spring.cloud.nacos.config.group}
metadata-report:
# 貌似下面这个配置也没什么作用
group: ${spring.cloud.nacos.config.group}
parameters:
# 貌似想配置dubbo注册到nacos的指定namespace下,好像不太行,即使这样配置了,也是在public下,如果有朋友知道如何配置,希望在评论中给予指正
namespace: ${spring.cloud.nacos.config.namespace}
- 启动主类
SpringbootDubboFeignNacosProducerApplication
内容如下:
@SpringBootApplication
@EnableDiscoveryClient
@EnableDubbo(scanBasePackages = "com.cyp.springbootdubbofeignnacosproducer.dubboapi")
public class SpringbootDubboFeignNacosProducerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDubboFeignNacosProducerApplication.class, args);
}
}
- dubbo接口实现
EchoDubboApi
内容如下:
@DubboService
public class EchoDubboApi implements IEchoDubbo {
@Override
public R<EchoDTO> echo(R<EchoDTO> dto) {
return dto;
}
}
- openfeign接口实现
EchoFeignApi
内容如下:
@RestController
public class EchoFeignApi implements IEchoFeign {
@Override
public R<EchoDTO> echo(R<EchoDTO> dto) {
return dto;
}
}
创建服务消费模块springboot-dubbo-feign-nacos-consumer
-
该模块主要结构如下:
image.png - 该模块的pom.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.cyp</groupId>
<artifactId>springboot-dubo-feign-nacos-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>springboot-dubbo-feign-nacos-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-dubbo-feign-nacos-consumer</name>
<description>springboot-dubbo-feign-nacos-consumer</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.cyp</groupId>
<artifactId>springboot-dubbo-feign-nacos-interface</artifactId>
<version>1.0</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- dubbo注册中心改为nacos的关键引用 -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!-- Introduce Dubbo Nacos extension, or you can add Nacos dependency directly as shown above-->
<!--<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>-->
</dependencies>
<build>
<finalName>app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 该模块的配置bootstrap.yml内容如下:
server:
port: 8080
spring:
application:
name: consumer-server
profiles:
active: test
cloud:
nacos:
username: nacos
password: nacos
# 照抄的朋友们,请把nacos的配置改为你们实际的nacos配置
server-addr: 127.0.0.1:8848
config:
group: DEFAULT_GROUP
prefix: application
file-extension: yaml
namespace: 4977df2a-9d19-4060-b82f-4d695704e165
dubbo:
application:
name: consumer-dubbo-server
# 该配置在producer-server中是没有的,但是在consumer这里要配置一下
# 如果不配置这个QOS的端口,它会延用dubbo自动生成的端口,在启动的时候,QOS注册就会提示该端口已经被使用的错误
# 虽然启动时有打印端口已经被使用的错误,但是依旧可以正常启动服务,并且dubbo也可以正常调用,但是为了解决启动报错还是加上这个端口
# 这个也是apache官方给出的解决方案,这个端口不能给-1,它不会自动找到一个可用的端口,给-1会报错,端口1-65535自己选择一个
qos-port: 3334
protocol:
name: dubbo
# port为-1表示自动找一个可用的端口
port: -1
registry:
address: nacos://${spring.cloud.nacos.server-addr}
username: ${spring.cloud.nacos.username}
password: ${spring.cloud.nacos.password}
group: ${spring.cloud.nacos.config.group}
protocol: nacos
metadata-report:
group: ${spring.cloud.nacos.config.group}
parameters:
namespace: ${spring.cloud.nacos.config.namespace}
- 该模块的启动类
SpringbootDubboFeignNacosConsumerApplication
内容如下:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.cyp.springbootdubbofeignnacosinterface.feign")
@EnableDubbo
public class SpringbootDubboFeignNacosConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDubboFeignNacosConsumerApplication.class, args);
}
}
- 该模块的
EchoApi
内容如下:
@Slf4j
@RestController
@RequestMapping("/test")
@RequiredArgsConstructor
public class EchoApi {
// 用于性能测试的对象
private final static R<EchoDTO> DTO = getR();
// openfeignClient直接使用构造注入
private final IEchoFeign echoFeign;
// dubbo服务要使用@DubboReference注解
@DubboReference
private IEchoDubbo echoDubbo;
@GetMapping("/feign")
public void echoFeign() {
StopWatch watch = new StopWatch();
watch.start();
IntStream.range(0, 100).forEach(a -> {
R<EchoDTO> feignR = echoFeign.echo(DTO);
});
watch.stop();
log.info("feign use {} ms", watch.getLastTaskTimeMillis());
}
@GetMapping("/dubbo")
public void echoDubbo() {
StopWatch watch = new StopWatch();
watch.start();
IntStream.range(0, 100).forEach(a -> {
R<EchoDTO> feignR = echoDubbo.echo(DTO);
});
watch.stop();
log.info("dubbo use {} ms", watch.getLastTaskTimeMillis());
}
private static R<EchoDTO> getR() {
try {
EchoDTO dto = new EchoDTO();
dto.setName("abcdefg");
// 照抄的朋友们,请把后面的图片改为你们本机上的某张图片
BufferedInputStream inputStream = FileUtil.getInputStream("E:/testImg/1.jpg");
byte[] bt = new byte[inputStream.available()];
inputStream.read(bt, 0, inputStream.available());
Map<String, String> map = new HashMap<>();
// 这里使用一张图片放到map两个key中的目的就是为了加大传输对象的体积
// 以便于在上面的循环中测试openfeign和dubbo的性能,算是其中之一的性能测试吧
map.put("k1", Base64.getEncoder().encodeToString(bt));
map.put("k2", Base64.getEncoder().encodeToString(bt));
dto.setMap(map);
R<EchoDTO> r = new R<>();
r.setCode(0);
r.setMsg("aaa");
r.setData(dto);
return r;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
-
通过调用springboot-dubbo-feign-nacos-consumer中的两个api接口,可以得出dubbo在本项目中的性能测试确实高于openfeign一倍左右
可能只是在当前场景下才只高出一倍左右,并没能像网上说的那样高几十倍.这是实测的结果,有图为证:
image.png 项目在启动的时候,producer服务提供方必须先启动,否则服务消费方会启动失败,这是使用dubbo的朋友都应该知道的规则
-
在服务提供者启动成功之后,nacos中可以看到produer在指定的namespace下自动创建了两个配置:
image.png -
并且在服务提供者启动成功后,在nacos的服务管理-服务列表-public中可以看到dubbo服务提供者的注册信息:
image.png -
并且在正常的namespace下还有服务本身的注册:
微信图片_20230403014439.png 我也不知道是不是我什么地方配置错误了才导致这样的注册情况,如果有知道的朋友,欢迎您在评论中指正,毕竟我也是第一次这样配置apache-dubbo
补充一下nacos配置中心里,我的applicat-test.yaml中的内容
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: 4977df2a-9d19-4060-b82f-4d695704e165
group: DEFAULT_GROUP
atest:
name: abcdeeeee
最后,给出我做这个整合的参考的所有网站地址:
- dubbo整合springboot的部署官网示例,示例中的dubbo使用的注册中心为zookeeper,只是参考了dubbo和springboot的相关引用:基于 Dubbo API 开发微服务应用 | Apache Dubbo
- springboot-springcloud-nacos组件的版本对应关系, 在这里弄明白这三大件之间的版本对应关系,然后在父工程pom.xml中配置相应的版本:版本说明 · alibaba/spring-cloud-alibaba Wiki · GitHub
- 使用阿里巴巴提供的 云原生应用脚手架 得到父工程中pom.xml的准确配置
- dubbo修改配置中心为Nacos:参考一 Nacos | Apache Dubbo 和 参考二 Nacos | Apache Dubbo
-
注意在参考一中,要求引用的只有:
微信图片_20230403014616.png
如果图片看不清楚以下是给出的引用
<dependencies>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.1.2</version>
</dependency>
</dependencies>
-
在参考二中,要求引用的又不一样:
微信图片_20230403014739.png
如果图片看不清楚以下是给出的引用
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.0.9</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Introduce Dubbo Nacos extension, or you can add Nacos dependency directly as shown above-->
<!--
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>3.0.9</version>
</dependency>
-->
- 多了一个org.apache.dubbo:dubbo的引用,但是在本项目中,去掉org.apache.dubbo:dubbo也能正常工作
- consumer启动的时候,没有添加QOS端口启动报错的解决参考:7-4 - QOS 服务启动失败 | Apache Dubbo 和 QOS 概述 | Apache Dubbo