实战springcloud alibaba
一、版本介绍
springcloud | springboot | springcloudalibaba | 持久层框架 | 注册中心/配置中心 | 熔断、限流 | 数据库 | 缓存/分布式锁 | 数据库连接池 | 远程调用 | 分布式事务 | 消息队列 | 定时任务 | 大数据存储 | 文档生成 | 链路追踪 | 服务监控 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2023.0.3 | 3.3.5 | 2023.0.1.2 | mybatis-flex1.10.9 | nacos2023.0.1.2(nacos服务端使用2.3.2) | sentinel2023.0.1.2(dashboard使用1.8.8) | mysql8 | redis | 德鲁伊 druid | open-feign | seata | kafka | xxl-job2.5.0 | elasticsearch7.9.3 | springdoc-openapi-starter-webmvc-ui | Sky walking | promothus+grafana |
二、组件nacos作注册中心、配置中心
2.1 导入包
<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>
这里的版本与springcloud alibaba一致:2023.0.1.2
2.2 配置yml(bootstrap.yml优先级高,所以配置nacos的连接写在bootstrap.yml)
spring:
application:
# 应用名称
name: mfcx-admin-service
profiles:
# 环境配置
active: dev
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: 192.168.174.192:8848
# namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
config:
# 配置中心地址
server-addr: 192.168.174.192:8848
# namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
# 配置文件格式
file-extension: yaml
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
extension-configs:
- data-id: mfcx-admin-service-bak-info.yaml
group: DEFAULT_GROUP
refresh: true
如上: 没有配置那么space,那么使用的是public,分组用的是DEFAULT_GROUP。
配置文件:
1、会读取默认的nacos配置文件名,文件如下:${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
例如,我的配置文件名为: mfcx-admin-service-dev.yaml
2、共享配置,即每个微服务都可以读取到:application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
例如:application-dev.yaml
3、延伸配置,即extension-configs指定的文件名 mfcx-admin-service-bak-info.yaml
2.3 注解
主启动类加上注解
@EnableDiscoveryClient
三、网关gateway
3.1 导入包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
注:
1.网关引入的是spring-cloud-starter-gateway
,而非spring-boot-starter-web
2.在SpringCloud 2020.* 以后版本把 bootstrap 禁用了,导致在读取文件的时候读取不到而报错,所以我们只要把spring-cloud-starter-bootstrap
从新导入进来就会生效了
3.Spring Cloud 2020 版本后移除了 Netflix Ribbon,spring-cloud-starter-loadbalancer 是其官方替代品: 为微服务间的 HTTP/RPC 调用提供 服务实例选择能力,并处理请求的负载均衡逻辑所以网关需引入spring-cloud-loadbalancer
如上使用的版本号分别为:4.1.5、4.1.4、4.1.4
3.2 配置动态路由
spring:
cloud:
gateway:
discovery:
locator:
lowerCaseServiceId: true
enabled: true
routes:
# 认证中心
- id: mfcx-auth-service
uri: lb://mfcx-auth-service
predicates:
- Path=/auth/**
filters:
- RewritePath=/auth/(?<segment>.*),/$\{segment}
- id: mfcx-admin-service
uri: lb://mfcx-admin-service
predicates:
- Path=/admin/**
filters:
#重写路径,例如:localhost:8080/admin/userInfo/queryUserInfoByUserId 在进入/mfcx-admin-service服务后路径为/userInfo/queryUserInfoByUserId
- RewritePath=/admin/(?<segment>.*),/$\{segment}
四、文档springdoc-openapi-starter-webmvc-ui
4.1 引入包
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
4.2 yml配置
springdoc:
api-docs:
enabled: true
path: /v3/api-docs
swagger-ui:
path: /swagger-ui.html
enabled: true
4.3 写配置类,可以分模块(每个类一个模块)
@Configuration
public class Swagger3Config {
/**
* 这里配置多模块,即每个控制器为一个分类,也可以不配置下面的Bean,那么就是该微服务所有接口都在一起
**/
@Bean
public GroupedOpenApi UserApi() {
return GroupedOpenApi.builder().group("系统用户模块").pathsToMatch("/userInfo/**").build();
}
@Bean
public GroupedOpenApi RoleApi() {
return GroupedOpenApi.builder().group("系统角色模块").pathsToMatch("/roleInfo/**", "/others").build();
}
/*@Bean
public GroupedOpenApi CustomerApi()
{
return GroupedOpenApi.builder().group("客户微服务模块").pathsToMatch("/customer/**",
"/customers").build();
}*/
@Bean
public OpenAPI docsOpenApi() {
return new OpenAPI()
.info(new Info().title("神雕出行")
.description("通用设计rest")
.version("v1.0"))
.externalDocs(new ExternalDocumentation()
.description("www.123.com")
.url("https://www.baidu.com/"));
}
}
4.4 注解
在类上面:
@Tag(name = "登录接口")
在方法上面:@Operation(summary = "登录")
在字段或属性类上面:@Schema(description = "用户名")
五、远程调用:open-feign的使用
5.1 消费方引入包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
5.2 标注解
消费方主启动类标注解 @EnableFeignClients(basePackages = “com.mfcx.cloud.feign”)
注意这里的feign接口在其他模块api,这里需要指定包路径
5.3 feign接口的编写
@FeignClient(value = "mfcx-auth-service",
path = "/remote/auth",
// configuration = FeignConfiguration.class,
fallback = AuthApiFeignClientCallBack.class)
public interface AuthApiFeignClient {
@PostMapping("/queryGoodsDetail")
List<GoodsDetailVO> queryGoodsDetail();
}
注:这里的value =
“mfcx-auth-service"与服务方的微服务名称一致,path的路径与feign接口的实现类上的注解@RequestMapping(”/remote/auth")一致
5.4 超时机制
spring:
cloud:
openfeign:
client:
config:
#全局超时配置
default:
# 连接超时时间 3秒
connectTimeout: 3000
# 读取超时时间 3秒
readTimeout: 3000
# mfcx-auth-service 服务的超时时间(他会覆盖全局配置)
mfcx-auth-service:
connectTimeout: 5000
readTimeout: 5000
5.5 设置重试机制
@Configuration
public class FeignConfig {
@Bean
public Retryer retryer() {
// 重试间隔时间,重试最大时间,最大重试次数(初始1次,重试2次)
return new Retryer.Default(1000, 1000, 3);
}
}
注:这里配置的是feign调用失败,允许再次尝试的参数
5.6 使用http client5 替换http,大幅提升性能
引入包
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hc5</artifactId>
</dependency>
修改配置
spring:
cloud:
openfeign:
#使用HttpClient5 替换http,参考官网:https://docs.spring.io/spring-cloud-openfeign/reference/spring-cloud-openfeign.html
httpclient:
hc5:
enabled: true
client:
config:
# openfeign全局超时时间配置
default:
# 连接超时时间 3秒
connectTimeout: 3000
# 读取超时时间 3秒
readTimeout: 3000
# mfcx-auth-service 服务的超时时间(他会覆盖全局配置)
mfcx-auth-service:
connectTimeout: 5000
readTimeout: 5000
5.7 对请求和响应进行GZIP压缩
对请求和响应进行GZIP压缩
Spring Cloud OpenFeign支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。
通过下面的两个参数设置,就能开启请求与相应的压缩功能:
开启请求压缩:spring.cloud.openfeign.compression.request.enabled=true
压缩的数据类型:spring.cloud.openfeign.compression.request.mime-types=text/xml,application/xml,application/json
触发压缩的大小:spring.cloud.openfeign.compression.request.min-request-size=2048
开启返回压缩 :spring.cloud.openfeign.compression.response.enabled=true
5.8 打印feign日志
配置类加一个Bean
@Configuration
public class FeignConfig {
@Bean
public Retryer retryer() {
// 重试间隔时间,重试最大时间,最大重试次数(初始1次,重试2次)
return new Retryer.Default(1000, 1000, 3);
}
//feign 提供了日志打印功能,我们可以通过配置来调整日志级别,
//从而了解 Feign 中 Http 请求的细节,
//说白了就是对Feign接口的调用情况进行监控和输出
@Bean
public Logger.Level logLevel() {
return Logger.Level.FULL;
}
}
yml配置
logging:
level:
com:
mfcx:
cloud:
feign:
AuthApiFeignClient: debug
注: 其中com.mfcx.cloud.feign.AuthApiFeignClient是接口(标记@FeignClient的接口),配置了日志,能清楚的看到远程调用的重试次数及失败原因
六、服务降级 sentinel
6.1 导包
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
6.2 yml配置
服务端连接sentinel大盘
spring:
sentinel:
transport:
dashboard: localhost:8080 #配置Sentinel dashboard控制台服务地址
port: 8719 #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
消费端激活Sentinel对Feign的支持
feign:
sentinel:
enabled: true
6.3 feign接口配置回退类,AuthApiFeignClientCallBack
@FeignClient(value = "mfcx-auth-service",
path = "/remote/auth",
fallbackFactory = AuthApiFeignClientCallback.class)
public interface AuthApiFeignClient {
@PostMapping("/queryUserInfo")
List<UserInfoResDTO> queryUserInfo(@RequestBody UserInfoReqDTO userInfo);
@PostMapping("/queryUser")
UserInfoResDTO queryUser();
@PostMapping("/queryUserByname")
CommonResult<List<UserInfoResDTO>> queryUserByName(@RequestBody UserInfoReqDTO userInfo);
}
6.4 编写回退类AuthApiFeignClientCallBack
@Component
@Slf4j
public class AuthApiFeignClientCallback implements FallbackFactory<AuthApiFeignClient> {
@Override
public AuthApiFeignClient create(Throwable cause) {
return new AuthApiFeignClient() {
@Override
public List<UserInfoResDTO> queryUserInfo(UserInfoReqDTO userInfo) {
log.error("[Fallback] 调用 mfcx-auth-service queryUserInfo失败,原因:{}", cause.getMessage());
return List.of();
}
@Override
public UserInfoResDTO queryUser() {
log.error("[Fallback] 调用 mfcx-auth-service queryUser失败,原因:{}", cause.getMessage());
return new UserInfoResDTO();
}
@Override
public CommonResult queryUserByName(UserInfoReqDTO userInfo) {
log.error("[Fallback] 调用 mfcx-auth-service queryUser失败,原因:{}", cause.getMessage());
CommonResult result = CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR);
return result;
}
};
}
}
6.5 显示声明回退类
因为AuthApiFeignClientCallBack 位于 mfcx-auth-api 模块,在消费方需要显示声明此对象
@Configuration
public class FeignConfig {
@Bean
public Retryer retryer() {
// 重试间隔时间,重试最大时间,最大重试次数(初始1次,重试2次)
return new Retryer.Default(1000, 1000, 3);
}
//feign 提供了日志打印功能,我们可以通过配置来调整日志级别,
//从而了解 Feign 中 Http 请求的细节,
//说白了就是对Feign接口的调用情况进行监控和输出
@Bean
public Logger.Level logLevel() {
return Logger.Level.FULL;
}
/**
* 显式声明回退工厂 Bean
* @return
*/
@Bean
public AuthApiFeignClientCallBack authApiFeignClientCallBack() {
return new AuthApiFeignClientCallBack();
}
}
七、sentinel实现网关限流
这里采用gateway+nacos+sentinel实现网关动态限流
7.1 引包
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel Gateway -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!-- Sentinel Datasource Nacos -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
7.2 主启动类加一行代码,添加此代码,在Sentinel控制台中做判断使用
System.setProperty("csp.sentinel.app.type", "1");
7.3 添加yml配置
spring:
cloud:
sentinel:
transport:
dashboard: 192.168.10.181:8858
port: 8719
eager: true
datasource:
ds1:
nacos:
# nacos地址
server-addr: 192.168.10.181:8848
# 配置文件名
data-id: gateway-flow-rule-sentinel
# 分组
group-id: DEFAULT_GROUP
# 类型
data-type: json
# 固定,网关流控
rule-type: gw-flow
#命名空间
namespace: 0b911c8b-a723-4af0-a4d0-9fa7c0a579bb
ds2:
nacos:
server-addr: 192.168.10.181:8848
data-id: gateway-flow-rule-api-sentinel
group-id: DEFAULT_GROUP
data-type: json
# 固定,分组流控
rule-type: gw-api-group
7.4 写两个配置类
加载nacos中的限流数据配置类
@Slf4j
@Configuration
public class GatewayConfiguration {
@Value("${spring.cloud.nacos.config.server-addr}")
private String nacosAddr;
@Value("${spring.cloud.nacos.config.group}")
private String group;
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@PostConstruct
public void doInit() {
// 注册 API 分组规则
ReadableDataSource<String, Set<ApiDefinition>> apiDefinitionSource =
new NacosDataSource<>(nacosAddr,
group,
"gateway-flow-rule-api-sentinel",
source -> JSON.parseObject(source, new TypeReference<>() {
}));
GatewayApiDefinitionManager.register2Property(apiDefinitionSource.getProperty());
// 注册网关限流规则
ReadableDataSource<String, Set<GatewayFlowRule>> flowRuleSource =
new NacosDataSource<>(nacosAddr,
group,
"gateway-flow-rule-sentinel",
source -> JSON.parseObject(source, new TypeReference<>() {
}));
GatewayRuleManager.register2Property(flowRuleSource.getProperty());
// 打印当前规则信息
Set<GatewayFlowRule> rules = GatewayRuleManager.getRules();
System.out.println("限流规则数量:" + rules.size());
rules.forEach(rule -> System.out.println("Rule: " + rule));
}
// @Bean
// @Order(Ordered.HIGHEST_PRECEDENCE)
// public GlobalFilter sentinelGatewayFilter() {
// return new SentinelGatewayFilter();
// }
}
限流返回数据格式配置类
@Configuration
public class SentinelGatewayConfig {
public SentinelGatewayConfig() {
GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {
// R error = R.error(500, "限流啦 别在试啦");
Map<Object,Object> map = new HashMap<>();
map.put(500, "限流啦 别在试啦");
String errorStr = JSON.toJSONString(map);
Mono<ServerResponse> just = ServerResponse.ok().body(Mono.just(errorStr), String.class);
return just;
}
});
}
}
7.5 nacos中的配置
文件 gateway-flow-rule-sentinel,格式 json
[
{
"resource": "mfcx-auth-service",
"resourceMode": 0,
"count": 15,
"intervalSec": 60
},
{
"resource": "mfcx-auth-service-api",
"resourceMode": 1,
"count": 4,
"intervalSec": 60
},
{
"resource": "mfcx-admin-service-api",
"resourceMode": 1,
"count": 5,
"intervalSec": 60
}
]
文件 gateway-flow-rule-api-sentinel ,格式:json
[{
"apiName": "mfcx-admin-service-api",
"predicateItems": [
{
"pattern": "/admin/feign/user/queryUserInfo"
},
{
"pattern":"/admin/feign/user/queryUser",
"matchStrategy": 0
}
]
}]
含义解释:
resource
:表示限流的资源名称,这里是针对认证服务整体进行限流
resourceMode
: 0=服务, 1=API, 2=自定义 流控粒度
count
: 在统计时间窗口内允许的最大请求数量
intervalSec
:统计时间窗口长度(秒)
apiName
:定义这组路由规则的名称标识,与resourceMode为1 的resource对应
predicateItems
: 路由断言规则数组,定义匹配请求路径的规则集合,决定哪些请求路径会被路由到目标分组
pattern
:路径匹配
matchStrategy
: 0=精确 1=前缀 2=正则 3=包含,默认为0
八、引入mybatis-flex
8.1 导包
<!--数据库相关-->
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mybatis-flex</groupId>
<artifactId>mybatis-flex-processor</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!--其中包含mybatis-spring-boot-starter-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<exclusions>
<!-- 保留 mybatis-spring-boot-starter 但排除特定传递依赖 -->
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
其中的版本号一次是:1.10.9、1.10.9、8.3.0、2.1.0
8.2 引入数据库相关配置
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://192.168.174.192:3307/tfx_user?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-flex:
mapper-locations: classpath*:/mapper/**/*.xml
configuration:
map-underscore-to-camel-case: true
至此,mybatis-flex就引入了项目。
Mapper层的写法,
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
实体类的写法
@Data
@Table("user_info")
public class UserInfo {
//雪花算法自动生成主键
@Id(keyType = KeyType.Generator,value = KeyGenerators.snowFlakeId)
private Long id;
private String name;
private String addr;
private Long roleId;
}