这里写自定义目录标题
前言
在springboot3不再兼容jdk8的时候,随之而来的便是各种框架不兼容引发的bug,虽然各位框架的开发大佬在加班加点的更新适配,但能够创建一个适用并且不报错的项目依旧是一件耗时耗力的事情。
我们都知道在String Cloud项目中默认使用Feign组件进行服务间的通信,REST API的调用方式使用起来十分的优雅、简洁,但通常情况下HTTP这种通信机制都是短连接,也就意味着每一次调用都是一次TCP连接的建立。无疑,这种方式的开销以及效率都有不小的问题。在对外部系统时使用REST API的方式去调用是个好方法,但在内部服务之间的调用中就会显得开销很大,所以,我们可以在内部服务之间使用RPC调用。
1、项目结构
在该demo中主要有以上四个项目:
parent: 父项目,所有依赖的管理包,在该项目的开发中,我们将所有的依赖以及依赖的版本都描述在parent项目中,在实际不同模块的开发中,我们只需要引入parent包,便可以在从中添加依赖而不再去关注依赖的版本。
provider: 服务提供方,用来提供服务的一方。
consumer: 服务消费方,负责消费服务。
common: 抽离出来的共组模块。在该模块中定义我们要调用的接口以及涉及到的entity、vo、dto等类,同时也可定义一些公用的工具类、枚举类等等
2、搭建nacos注册中心、配置中心
此处不过多详细描述,下载并安装配置nacos即可
3、项目依赖
项目中的所有依赖都在parent项目中进行管理,所以我们这里先看parent的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fawu</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.4</version>
</parent>
<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.4</spring-boot.version>
<spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version>
<spring-cloud.version>2022.0.0</spring-cloud.version>
<dubbo.version>3.3.0-beta.1</dubbo.version>
<mybatis-plus.version>3.5.1</mybatis-plus.version>
<druid.version>1.2.8</druid.version>
<mapstruct.version>1.4.1.Final</mapstruct.version>
<hutool.version>5.8.20</hutool.version>
<lombok.version>1.18.26</lombok.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
<spring-cloud-bootstrap.version>4.0.3</spring-cloud-bootstrap.version>
<poi.version>4.1.2</poi.version>
<fastjson.version>2.0.32</fastjson.version>
<commons-i3o.version>1.3.2</commons-i3o.version>
</properties>
<dependencyManagement>
<!-- SpringBoot 依赖配置 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringCloud 微服务 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- SpringCloud Alibaba 微服务 -->
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>${spring-cloud-bootstrap.version}</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!-- Alibaba Spring Context extension -->
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
<version>1.0.11</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- mapstruct 对象拷贝-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- common io -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>none</mainClass> <!-- 取消查找本项目下的Main方法:为了解决Unable to find main class的问题 -->
<classifier>execute</classifier> <!-- 为了解决依赖模块找不到此模块中的类或属性 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
其中的主要依赖为上图所示,依赖版本都是Springboot3.x之后适配的版本。
4、common模块
在该模块中我们需要配置需要调用的接口。首先来看一下他的依赖
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.fawu</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>common</name>
<description>common</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</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>
<build>
<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>
我们可以看到在pom文件的开头有如下配置:
xml
<parent>
<groupId>com.fawu</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
进行该配置后即可引用parent管理的依赖版本,不需要再去关注依赖的版本了。其余的便是常规的一些依赖。
然后便是需要在该项目中创建在服务消费者中调用,在服务提供者中实现的接口:
java
public interface UserService {
/**
* 测试登录接口
* @param username
* @return
*/
String login(String username);
}
5、provider服务提供者
该模块用来提供服务,也就是实现在common模块中提出的login接口。
pom文件
照例先看一下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.fawu</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>Provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ProviderDemo</name>
<description>服务提供者</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.fawu</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!-- Alibaba Spring Context extension -->
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
</dependencies>
<build>
<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>
我们可以看到在该项目中引入了spring-cloud-starter-alibaba-nacos-discovery
、spring-cloud-starter-alibaba-nacos-config
、spring-cloud-starter-bootstrap
、dubbo
依赖。
其中spring-cloud-starter-alibaba-nacos-discovery
是使用nacos作为注册中心的依赖,spring-cloud-starter-alibaba-nacos-config
是使用nacos作为配置中心的依赖,spring-cloud-starter-bootstrap
为配置读取bootstrap配置的依赖,dubbo
即为使用RPC进行通讯的依赖。
bootstrap.yml
接下来对模块进行配置,创建bootstrap.yml文件
yml
server:
port: 8087
spring:
application:
name: providerDemo
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
enabled: true
register-enabled: true
namespace: demo
group: DEFAULT_GROUP
config:
server-addr: 127.0.0.1:8848
extension-configs[0]:
data-id: providerDemo.yaml
group: DEFAULT_GROUP
refresh: true
file-extension: yml
namespace: demo
group: DEFAULT_GROUP
我们可以看到在该配置中配置了端口号,配置了nacos作为注册中心时的地址以及命名空间、分组,配置了nacos作为配置中心的地址以及要加载的配置的dataId、分组。
在nacos中添加配置
此时我们打开nacos的地址
http://127.0.0.1:8848/nacos/index.html
1)、创建命名空间
选择命名空间
点击新建命名空间
创建demo命名空间
2)、添加配置
打开配置管理/配置列表,选择我们刚刚创建的demo的空间,点击创建配置。
创建providerDemo.yaml配置,配置内容如下:
yml
spring:
# 前后端传输时间相差8小时问题
jackson:
time-zone:
GMT+8
date-format:
yyyy-MM-dd HH:mm:ss
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/bot?useUnicode=true&characterEncoding=utf8&nullCatalogMeansCurrent=true& useSSL=false&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8&serverTimezone=Asia/Shanghai
username: root
password: root
redis:
# Redis数据库索引(默认为0)
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间(毫秒)
timeout: 3000
mybatis:
configuration:
cache-enabled: false
map-underscore-to-camel-case: true
mapper-locations: classpath:mapping/**/*Mapper.xml
type-aliases-package: com.onlyoa.common.entity
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: true
params: count=countSql
page-size-zero: true
dubbo:
cloud:
subscribed-services: consumerDemo
scan:
#指定 Dubbo 服务实现类的扫描基准包
base-packages: com.fawu
protocol:
#使用dubbo协议
name: dubbo
# port 为协议端口( -1 表示自增端口,从 20880 开始)
port: -1
registry:
#配置中心nacos地址
address: nacos://127.0.0.1:8848
config-center:
namespace: demo
consumer:
timeout: 300000
user:
test:
userId: 123456
我们可以看到在该配置中和我们常规springboot项目中的配置文件基本相似,只是多了一个dubbo的配置项。
启动类
java
@SpringBootApplication
@EnableDubbo
@EnableDiscoveryClient
public class ProviderDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderDemoApplication.class, args);
}
}
我们可以看到启动类上多出了@EnableDubbo
、@EnableDiscoveryClient
两个注解,顾名思义,一个为dubbo的配置注解,一个为注册中心的配置注解。
UserServiceImpl
终于到了服务的实现了,在该模块中我们引入了
xml
<dependency>
<groupId>com.fawu</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
也就是我们在前面所编写的仅有一个接口的common模块。接下来我们来实现该接口。
java
import com.fawu.common.service.UserService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Value;
/**
* 用户服务层实现
*
* @author <a href="https://github.com/fawu-K">fawu.K</a>
* @since 2024-03-16 14:44
**/
@DubboService
public class UserServiceImpl implements UserService {
@Value("${user.test.userId}")
private String userId;
@Override
public String login(String username) {
if (userId.equals(username)) {
return "账号正确!";
} else {
return "账号错误!";
}
}
}
需要注意,在该类上添加了@DubboService
注解,该注解表明了这是一个dubbo服务,即可以通过RPC进行调用的服务。
consumer服务消费者
pom文件
照例,看一下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.fawu</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>Consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ConsumerDemo</name>
<description>服务消费者</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.fawu</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
</dependencies>
<build>
<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
yml
server:
port: 7777
spring:
application:
name: consumerDemo
cloud:
nacos:
discovery:
server-addr: http://127.0.0.1:8848/
enabled: true
register-enabled: true
namespace: demo
group: DEFAULT_GROUP
config:
server-addr: 127.0.0.1:8848
extension-configs[0]:
data-id: consumerDemo.yaml
group: DEFAULT_GROUP
refresh: true
file-extension: yml
namespace: demo
group: DEFAULT_GROUP
此配置依旧和服务提供者的配置基本相同,只有配置的data-id不同
nacos配置
打开nacos网址创建配置
配置内容:
yml
spring:
# 前后端传输时间相差8小时问题
jackson:
time-zone:
GMT+8
date-format:
yyyy-MM-dd HH:mm:ss
servlet:
multipart:
max-file-size: 100MB
max-request-size: 100MB
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/bot?useUnicode=true&characterEncoding=utf8&nullCatalogMeansCurrent=true& useSSL=false&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8&serverTimezone=Asia/Shanghai
username: root
password: root
redis:
# Redis数据库索引(默认为0)
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
# 连接超时时间(毫秒)
timeout: 3000
cloud:
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: 127.0.0.1:8848
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直到找到未被占用的端口
port: 8719
datasource:
dsl:
nacos:
server-addr: 127.0.0.1:8848 #配置中心nacos地址
namespace: demo #配置nacos地址
dataId: onlyone-consumer-sentinel
groupId: SENTINEL_GROUP
data-type: json
rule-type: flow
dubbo:
registry:
#配置中心nacos地址
address: nacos://127.0.0.1:8848
scan:
#指定 Dubbo 服务实现类的扫描基准包
base-packages: com.fawu
cloud:
subscribed-services: providerDemo
application:
qos-enable: false
name: consumerDemo
config-center:
namespace: demo
protocol:
#使用dubbo协议
name: dubbo
# port 为协议端口( -1 表示自增端口,从 20880 开始)
port: -1
consumer:
timeout: 300000
mybatis:
configuration:
cache-enabled: false
map-underscore-to-camel-case: true
mapper-locations: classpath:mapping/**/*Mapper.xml
type-aliases-package: com.onlyoa.common.entity
sftp:
# 服务器地址
host: 127.0.0.1
# 端口
port: 22
# 账号
userName: root
# 密码
password: root
# 图片的根路径
basePath: /home/nginx/image
# 音频的根路径
audioPath: /home/nginx/audio
# 视频的根路径
videoPath: /home/nginx/video
# channel连接超时时间
timeout: 30000
#连接次数
count: 3
#休眠时间
sleepTime: 6000
#服务器头像地址
titleImgsPath: http://127.0.0.1:80/image/
#服务器音频地址
titleAudiosPath: http://127.0.0.1:80/audio/
#服务器视频地址
titleVideosPath: http://127.0.0.1:80/video/
启动类
java
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
@EnableDubbo
public class ConsumerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerDemoApplication.class, args);
}
}
UserController
java
import com.fawu.common.service.UserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 用户控制层
*
* @author <a href="https://github.com/fawu-K">fawu.K</a>
* @since 2024-03-16 14:47
**/
@RestController
public class UserController {
@DubboReference
private UserService userService;
@GetMapping("login")
public String login(String username) {
return userService.login(username);
}
}
对于使用dubboRPC调用的服务使用@DubboReference
注解进行调用。
测试
http://127.0.0.1:7777/login?username=123456
此时我们调用login接口,就会看到如下内容:
当然了也可以是改一下username: