Skip to content

Commit

Permalink
init gateway
Browse files Browse the repository at this point in the history
  • Loading branch information
Yingbo Wang committed Oct 18, 2022
1 parent 89e1b2e commit abb2e65
Show file tree
Hide file tree
Showing 16 changed files with 1,141 additions and 1 deletion.
11 changes: 10 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<cloud-alibaba.version>2.2.7.RELEASE</cloud-alibaba.version>
<spring-boot.version>2.3.12.RELEASE</spring-boot.version>
<spring-cloud.version>Spring Cloud Hoxton.SR9</spring-cloud.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
</properties>

<modules>
Expand All @@ -29,6 +29,7 @@
<module>rms-mall-mvc-config</module>
<module>rms-mall-nacos-client</module>
<module>rms-mall-admin</module>
<module>rms-mall-gateway</module>
</modules>

<dependencies>
Expand Down Expand Up @@ -115,6 +116,14 @@
<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>

</dependencies>
</dependencyManagement>

Expand Down
62 changes: 62 additions & 0 deletions rms-mall-gateway/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?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>rms-mall</artifactId>
<groupId>com.wyb.rms</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>rms-mall-gateway</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<!-- 模块名及描述信息 -->
<name>e-rms-mall-gateway</name>
<description>Spring Cloud Gateway</description>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<dependency>
<groupId>com.wyb.rms</groupId>
<artifactId>rms-mall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>

<!--
SpringBoot的Maven插件, 能够以Maven的方式为应用提供SpringBoot的支持,可以将
SpringBoot应用打包为可执行的jar或war文件, 然后以通常的方式运行SpringBoot应用
-->
<build>
<finalName>${artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.wyb.rms.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
* <h1>网关启动入口</h1>
* */
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayApplication {

public static void main(String[] args) {

SpringApplication.run(GatewayApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package com.wyb.rms.gateway.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
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 reactor.core.publisher.Mono;

import java.util.List;

/**
* 事件推送 Aware: 动态更新路由网关 Service
* */
@Slf4j
@Service
@SuppressWarnings("all")
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {

/** 写路由定义 */
private final RouteDefinitionWriter routeDefinitionWriter;
/** 获取路由定义 */
private final RouteDefinitionLocator routeDefinitionLocator;

/** 事件发布 */
private ApplicationEventPublisher publisher;

public DynamicRouteServiceImpl(RouteDefinitionWriter routeDefinitionWriter,
RouteDefinitionLocator routeDefinitionLocator) {
this.routeDefinitionWriter = routeDefinitionWriter;
this.routeDefinitionLocator = routeDefinitionLocator;
}

@Override
public void setApplicationEventPublisher(
ApplicationEventPublisher applicationEventPublisher) {
// 完成事件推送句柄的初始化
this.publisher = applicationEventPublisher;
}

/**
* <h2>增加路由定义</h2>
* */
public String addRouteDefinition(RouteDefinition definition) {

log.info("gateway add route: [{}]", definition);

// 保存路由配置并发布
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
// 发布事件通知给 Gateway, 同步新增的路由定义
this.publisher.publishEvent(new RefreshRoutesEvent(this));

return "success";
}

/**
* <h2>更新路由</h2>
* */
public String updateList(List<RouteDefinition> definitions) {

log.info("gateway update route: [{}]", definitions);

// 先拿到当前 Gateway 中存储的路由定义
List<RouteDefinition> routeDefinitionsExits =
routeDefinitionLocator.getRouteDefinitions().buffer().blockFirst();
if (!CollectionUtils.isEmpty(routeDefinitionsExits)) {
// 清除掉之前所有的 "旧的" 路由定义
routeDefinitionsExits.forEach(rd -> {
log.info("delete route definition: [{}]", rd);
deleteById(rd.getId());
});
}

// 把更新的路由定义同步到 gateway 中
definitions.forEach(definition -> updateByRouteDefinition(definition));
return "success";
}

/**
* <h2>根据路由 id 删除路由配置</h2>
* */
private String deleteById(String id) {

try {
log.info("gateway delete route id: [{}]", id);
this.routeDefinitionWriter.delete(Mono.just(id)).subscribe();
// 发布事件通知给 gateway 更新路由定义
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "delete success";
} catch (Exception ex) {
log.error("gateway delete route fail: [{}]", ex.getMessage(), ex);
return "delete fail";
}
}

/**
* <h2>更新路由</h2>
* 更新的实现策略比较简单: 删除 + 新增 = 更新
* */
private String updateByRouteDefinition(RouteDefinition definition) {

try {
log.info("gateway update route: [{}]", definition);
this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
} catch (Exception ex) {
return "update fail, not find route routeId: " + definition.getId();
}

try {
this.routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
} catch (Exception ex) {
return "update route fail";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.wyb.rms.gateway.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;

/**
* <h1>通过 nacos 下发动态路由配置, 监听 Nacos 中路由配置变更</h1>
* */
@Slf4j
@Component
@DependsOn({"gatewayConfig"})
public class DynamicRouteServiceImplByNacos {

/** Nacos 配置服务 */
private ConfigService configService;
private final DynamicRouteServiceImpl dynamicRouteService;

public DynamicRouteServiceImplByNacos(DynamicRouteServiceImpl dynamicRouteService) {
this.dynamicRouteService = dynamicRouteService;
}

/**
* <h2>Bean 在容器中构造完成之后会执行 init 方法</h2>
* */
@PostConstruct
public void init() {

log.info("gateway route init....");

try {
// 初始化 Nacos 配置客户端
configService = initConfigService();
if (null == configService) {
log.error("init config service fail");
return;
}

// 通过 Nacos Config 并指定路由配置路径去获取路由配置
String configInfo = configService.getConfig(
GatewayConfig.NACOS_ROUTE_DATA_ID,
GatewayConfig.NACOS_ROUTE_GROUP,
GatewayConfig.DEFAULT_TIMEOUT
);

log.info("get current gateway config: [{}]", configInfo);
List<RouteDefinition> definitionList =
JSON.parseArray(configInfo, RouteDefinition.class);

if (CollectionUtils.isNotEmpty(definitionList)) {
for (RouteDefinition definition : definitionList) {
log.info("init gateway config: [{}]", definition.toString());
dynamicRouteService.addRouteDefinition(definition);
}
}

} catch (Exception ex) {
log.error("gateway route init has some error: [{}]", ex.getMessage(), ex);
}

// 设置监听器
dynamicRouteByNacosListener(GatewayConfig.NACOS_ROUTE_DATA_ID,
GatewayConfig.NACOS_ROUTE_GROUP);
}

/**
* <h2>初始化 Nacos Config</h2>
* */
private ConfigService initConfigService() {

try {
Properties properties = new Properties();
properties.setProperty("serverAddr", GatewayConfig.NACOS_SERVER_ADDR);
properties.setProperty("namespace", GatewayConfig.NACOS_NAMESPACE);
return configService = NacosFactory.createConfigService(properties);
} catch (Exception ex) {
log.error("init gateway nacos config error: [{}]", ex.getMessage(), ex);
return null;
}
}

/**
* <h2>监听 Nacos 下发的动态路由配置</h2>
* */
private void dynamicRouteByNacosListener(String dataId, String group) {

try {
// 给 Nacos Config 客户端增加一个监听器
configService.addListener(dataId, group, new Listener() {

/**
* <h2>自己提供线程池执行操作</h2>
* */
@Override
public Executor getExecutor() {
return null;
}

/**
* <h2>监听器收到配置更新</h2>
* @param configInfo Nacos 中最新的配置定义
* */
@Override
public void receiveConfigInfo(String configInfo) {

log.info("start to update config: [{}]", configInfo);
List<RouteDefinition> definitionList =
JSON.parseArray(configInfo, RouteDefinition.class);
log.info("update route: [{}]", definitionList.toString());
dynamicRouteService.updateList(definitionList);
}
});
} catch (NacosException ex) {
log.error("dynamic update gateway config error: [{}]", ex.getMessage(), ex);
}
}
}
Loading

0 comments on commit abb2e65

Please sign in to comment.