springcloudtencetn 父工程:
pom
<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.0modelVersion>
<groupId>com.gtongroupId>
<artifactId>cloudartifactId>
<packaging>pompackaging>
<version>0.0.1-SNAPSHOTversion>
<modules>
<module>gatewaymodule>
<module>usermanagermodule>
<module>commoditymodule>
<module>back-stage-managementmodule>
<module>commonmodule>
modules>
<name>cloudname>
<description>Spring Cloud Tencent +北极星(服务管理 流量管理 故障容错 配置管理) 微服务架构系统description>
<properties>
<java.version>11java.version>
<maven.compiler.source>11maven.compiler.source>
<maven.compiler.target>11maven.compiler.target>
<spring-cloud-tencent-version>1.7.0-2021.0.3spring-cloud-tencent-version>
<spring-cloud-dependencies-version>2021.0.3spring-cloud-dependencies-version>
<projectlombok-version>1.18.16projectlombok-version>
<spring-boot.version>2.6.9spring-boot.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.cloudgroupId>
<artifactId>spring-cloud-tencent-dependenciesartifactId>
<version>${spring-cloud-tencent-version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud-dependencies-version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.16version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.1version>
<configuration>
<source>11source>
<target>11target>
<encoding>UTF-8encoding>
configuration>
plugin>
plugins>
build>
project>
gateway导入pom
<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">
<parent>
<artifactId>cloudartifactId>
<groupId>com.gtongroupId>
<version>0.0.1-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>gatewayartifactId>
<properties>
<fastJson-version>2.0.18fastJson-version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>com.tencent.cloudgroupId>
<artifactId>spring-cloud-starter-tencent-polaris-routerartifactId>
dependency>
<dependency>
<groupId>com.tencent.cloudgroupId>
<artifactId>spring-cloud-starter-tencent-polaris-discoveryartifactId>
dependency>
<dependency>
<groupId>com.tencent.cloudgroupId>
<artifactId>spring-cloud-starter-tencent-polaris-ratelimitartifactId>
dependency>
<dependency>
<groupId>com.tencent.cloudgroupId>
<artifactId>spring-cloud-starter-tencent-polaris-configartifactId>
dependency>
<dependency>
<groupId>com.tencent.cloudgroupId>
<artifactId>spring-cloud-starter-tencent-polaris-circuitbreakerartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-loadbalancerartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-bootstrapartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-circuitbreaker-spring-retryartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>com.alibaba.fastjson2groupId>
<artifactId>fastjson2artifactId>
<version>${fastJson-version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
dependencies>
project>
网关配置:
spring:
application:
name: gateway
cloud:
gateway:
discovery:
locator:
# 开启从注册中心动态创建路由的功能,利用微服务名进行路由
enabled: true
polaris:
address: grpc://localhost:8091 #北极星注册中心地址
namespace: polaris-cloud-market #北极星注册中心的使用命名空间,自定义
config:
auto-refresh: true #当配置发布后,动态刷新
address: grpc://localhost:8093 # 当配置中心和 注册中心地址不一致时可以选择,否着可以不填
groups:
- name: gatewayOnly #读取的文件所在分组
files: ["router.properties","myconfig.yaml"] #读取的文件名
北极星控制台配置
gateway网关的路由操作类:
package com.gton.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* @description:动态更新路由网关service
* @author: GuoTong
* @createTime: 2022-10-05 22:24
* @since JDK 1.8 OR 11
**/
@Slf4j
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
@Autowired
private RouteDefinitionLocator routeDefinitionLocator;
/**
* 发布事件
*/
@Autowired
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
/**
* 删除路由
*
* @param id
* @return
*/
public String delete(String id) {
try {
log.info("gateway delete route id {}", id);
this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "delete success";
} catch (Exception e) {
return "delete fail";
}
}
/**
* 更新路由
*
* @param definitions
* @return
*/
public String updateList(List definitions) {
log.info("gateway update route {}", definitions);
// 删除缓存routerDefinition
List routeDefinitionsExits = routeDefinitionLocator.getRouteDefinitions().buffer().blockFirst();
if (!CollectionUtils.isEmpty(routeDefinitionsExits)) {
routeDefinitionsExits.forEach(routeDefinition -> {
log.info("delete routeDefinition:{}", routeDefinition);
delete(routeDefinition.getId());
});
}
definitions.forEach(this::updateById);
return "success";
}
/**
* 更新路由
*
* @param definition
* @return
*/
public String updateById(RouteDefinition definition) {
try {
log.info("gateway update route {}", definition);
this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
} catch (Exception e) {
return "update fail,not find route routeId: " + definition.getId();
}
try {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
} catch (Exception e) {
return "update route fail";
}
}
/**
* 增加路由
*
* @param definition
* @return
*/
public String add(RouteDefinition definition) {
log.info("gateway add route {}", definition);
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
}
}
监听路由变化
package com.gton.listener;
import com.alibaba.fastjson2.JSONObject;
import com.gton.service.DynamicRouteServiceImpl;
import com.tencent.cloud.polaris.config.annotation.PolarisConfigKVFileChangeListener;
import com.tencent.cloud.polaris.config.listener.ConfigChangeEvent;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.configuration.api.core.ChangeType;
import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Component;
import java.net.URI;
import java.util.*;
/**
* @description: 监听Polaris的配置更新
* @author: GuoTong
* @createTime: 2022-11-24 22:25
* @since JDK 1.8 OR 11
**/
@Component
@Slf4j
@SuppressWarnings("all")
public class ListenerPolaris {
@Autowired
private DynamicRouteServiceImpl dynamicRouteService;
/**
* PolarisConfigKVFileChangeListener Example .
* 监听北极星中心变更路由
*
* @param event instance of {@link ConfigChangeEvent}
*/
@PolarisConfigKVFileChangeListener(interestedKeyPrefixes = "routes")
public void onChange(ConfigChangeEvent event) {
// 封装需要更新的路由规则数据
List routeUpdates = new ArrayList<>();
// 获取配置修改的所有key
Set changedKeys = event.changedKeys();
// 保留已经处理的
Set intIndex = new HashSet<>();
for (String changedKey : changedKeys) {
// 获取修改的实体
ConfigPropertyChangeInfo changeInfo = event.getChange(changedKey);
if (changeInfo.getChangeType() == ChangeType.ADDED) {
String newValue = changeInfo.getNewValue();
// 添加新路由
addNewRule(routeUpdates, newValue);
}
// 删除老路由(弃用)
if (changeInfo.getChangeType() == ChangeType.DELETED) {
String newValue = changeInfo.getNewValue();
JSONObject jsonObject = JSONObject.parseObject(newValue);
String id = jsonObject.getString("id");
dynamicRouteService.delete(id);
}
if (CollectionUtils.isNotEmpty(routeUpdates)) {
routeUpdates.forEach(item -> dynamicRouteService.add(item));
}
}
}
/**
* Description: 添加新路由
*
* @param routeUpdates
* @param changeInfo
* @author: GuoTong
* @date: 2022-11-25 15:32:59
* @return:void
*/
public void addNewRule(List routeUpdates, String newValue) {
RouteDefinition routeDefinition = new RouteDefinition();
JSONObject jsonObject = JSONObject.parseObject(newValue);
routeDefinition.setId(jsonObject.getString("id"));
routeDefinition.setUri(URI.create(jsonObject.getString("uri")));
List predicates = routeDefinition.getPredicates();
String predicates1 = jsonObject.getString("predicates");
if (predicates1.contains(";")) {
String[] split = predicates1.split(";");
for (String vars : split) {
String[] var3 = vars.split("=");
PredicateDefinition predicateDefinition = new PredicateDefinition();
predicateDefinition.setName(var3[0]);
Map args = predicateDefinition.getArgs();
args.put(var3[0], var3[1]);
predicates.add(predicateDefinition);
}
} else {
String[] split = predicates1.split("=");
PredicateDefinition predicateDefinition = new PredicateDefinition();
predicateDefinition.setName(split[0]);
Map args = predicateDefinition.getArgs();
args.put(split[0], split[1]);
predicates.add(predicateDefinition);
}
List filters = routeDefinition.getFilters();
String var6 = jsonObject.getString("filters");
if (var6.contains(";")) {
String[] var7 = var6.split(";");
for (String var8 : var7) {
String[] split = var8.split("=");
FilterDefinition filterDefinition = new FilterDefinition();
filterDefinition.setName(split[0]);
Map args = filterDefinition.getArgs();
args.put(split[0], split[1]);
filters.add(filterDefinition);
}
} else {
String[] split = var6.split("=");
FilterDefinition filterDefinition = new FilterDefinition();
filterDefinition.setName(split[0]);
Map args = filterDefinition.getArgs();
args.put(split[0], split[1]);
filters.add(filterDefinition);
}
routeUpdates.add(routeDefinition);
}
}
初始化读取配置
package com.gton.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @description: 读取北极星配置路由
* @author: GuoTong
* @createTime: 2022-11-25 15:55
* @since JDK 1.8 OR 11
**/
@ConfigurationProperties(prefix = "routes")
@Component
@Data
public class ReadRouterConfig {
/**
* Description: 网关路由动态配置
*
* @author: GuoTong
* @date: 2022-11-25 16:08:23
* @param rule
* @return:
*/
private List rule;
}
启动加载配置问阿金
package com.gton.config;
import com.gton.listener.ListenerPolaris;
import com.gton.service.DynamicRouteServiceImpl;
import com.tencent.polaris.api.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @program: PersonalDesign
* @description: 项目一启动就执行
**/
@Slf4j
@Component
@Order(value = 1)
public class MyApplicationRunner implements ApplicationRunner {
@Autowired
private ReadRouterConfig readRouterConfig;
@Autowired
private ListenerPolaris listenerPolaris;
@Autowired
private DynamicRouteServiceImpl dynamicRouteService;
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("开始网关路由配置加载。。。。。。");
// 读取北极星上的配置信息
List rule = readRouterConfig.getRule();
List routeUpdates = new ArrayList<>();
// 北极星上的配置处理
rule.forEach(item -> listenerPolaris.addNewRule(routeUpdates, item));
if (log.isDebugEnabled()) {
log.debug("加载的路由配置是->{}", routeUpdates);
}
// 启动完成注册相关路由配置
if (CollectionUtils.isNotEmpty(routeUpdates)) {
routeUpdates.forEach(item -> dynamicRouteService.add(item));
}
log.info("网关路由配置加载结束。。。。。。");
}
}
到此结束!!!!