pom
<?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.gton</groupId>
<artifactId>cloud</artifactId>
<packaging>pom</packaging>
<version>0.0.1-SNAPSHOT</version>
<modules>
<module>gateway</module>
<module>usermanager</module>
<module>commodity</module>
<module>back-stage-management</module>
<module>common</module>
</modules>
<name>cloud</name>
<description>Spring Cloud Tencent +北极星(服务管理 流量管理 故障容错 配置管理) 微服务架构系统</description>
<properties>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<spring-cloud-tencent-version>1.7.0-2021.0.3</spring-cloud-tencent-version>
<spring-cloud-dependencies-version>2021.0.3</spring-cloud-dependencies-version>
<projectlombok-version>1.18.16</projectlombok-version>
<spring-boot.version>2.6.9</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-dependencies</artifactId>
<version>${spring-cloud-tencent-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-dependencies-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
<?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">
<parent>
<artifactId>cloud</artifactId>
<groupId>com.gton</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway</artifactId>
<properties>
<fastJson-version>2.0.18</fastJson-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--网关路由-->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<!--服务注册与发现-->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
</dependency>
<!--服务限流-->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-ratelimit</artifactId>
</dependency>
<!--北极星配置中心-->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-config</artifactId>
</dependency>
<!--北极星熔断-->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-circuitbreaker</artifactId>
</dependency>
<!--负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- bootstrap最高级启动配置读取 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-circuitbreaker-spring-retry</artifactId>
</dependency>
<!--使用gateway做网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastJson-version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</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"] #读取的文件名
北极星控制台配置
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<RouteDefinition> definitions) {
log.info("gateway update route {}", definitions);
// 删除缓存routerDefinition
List<RouteDefinition> 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<RouteDefinition> routeUpdates = new ArrayList<>();
// 获取配置修改的所有key
Set<String> changedKeys = event.changedKeys();
// 保留已经处理的
Set<String> 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<RouteDefinition> 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<PredicateDefinition> 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<String, String> 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<String, String> args = predicateDefinition.getArgs();
args.put(split[0], split[1]);
predicates.add(predicateDefinition);
}
List<FilterDefinition> 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<String, String> 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<String, String> 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<String> 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<String> rule = readRouterConfig.getRule();
List<RouteDefinition> 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("网关路由配置加载结束。。。。。。");
}
}
到此结束!!!!