业务流程
在第15章节中我们已经实现了在api-gateway-assist
中从网关中心api-gateway-center
中拉取配置,但是我们在15章节中并没有对这个配置信息做任何处理,仅仅是拉取了下来。但是我们要记住我们的目的时用这个配置在网关核心通信组件上执行,来进行远程服务的调用。那么如何将拉取下来的配置运用到我们的网关核心通信组件api-gateway-core
上呢?在之前的设计中我们提到过,我们的api-gateway-assist是一个类似于starter的对api-gateway-core
的包装,而无论是是springboot的starter还是Dubbo的starter,这个starter只要引入,那么就可以通过这个starter使用starter包装的方法,并且查看相关的starter资源resource包,会发现你只引入了一个starter却同时也引入了其starter包装的内容进来。这就表示我们在starter中的pom依赖其实是引入了我们被包装的那一部分内容,而后续的对starter的打包时也会将包装内容一起打包引入,后续的东西只需要引入starter就可以获得对应的所有功能。
因此,这里api-gateway-assist拉取到到的配置如何放入通信组件api-gateway-core
呢?
将通信组件
api-gateway-core
打包引入api-gateway-assist
中,api-gateway-assist
解析配置信息后直接调用通信组件api-gateway-core
即可。
但是这里还有一个问题,我们之前对于 api-gateway-core
的开发中,对于配置下 的Netty 服务的IP地址和端口信息是写死的,而我们在api-gateway-assist
中的application.xml
中确实有配置文件指定的(这也是之前写 api-gateway-core中一直提到的要用配置文件来配置Configuration),因此
在第16章中,我们先提取 Netty 通信服务配置信息,包括:IP、端口、线程等,到会话的 Configuration 配置类中进行统一的维护和管理,便于外部调用方向内部传递信息。
在本章节的第17章中,我们会在第15章的基础上继续完善服务发现的相关功能,把从注册中心拉取的网关映射信息【系统、接口、方法】映射到本地通信组件中。这样就算完成了注册中心到本地服务的一个打通处理,映射完成后就可以通过HTTP请求到网关通信层,完成对RPC的泛化调用。
第16,17章最好一起看,深度关联
如下图(图片来自于xfg)
业务实现
网关通信组件打包引入
首先我们将网关通信组件api-gateway-core
进行打包,让api-gateway-assist
引入,
mavean点击install打包后,我们就可以在api-gateway-assist中引入
<!--引入网关核心通信组件 api-gateway-core-->
<dependency>
<groupId>com.zshunbao.gateway</groupId>
<artifactId>api-gateway-core-09</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
同时我们提到过,我们希望我们后续无论什么引入了api-gateway-assist
这个starter,它也都可以使用到这个starter引入的网关通信组件功能,因此我们在pom文件中途还需要添加一项配置,以便后续api-gateway-assist
打包可以带上其引入的api-gateway-core
的相关配置
<configuration>
<artifactSet>
<includes>
<include>com.zshunbao.gateway:api-gateway-core-09:jar:</include>
</includes>
</artifactSet>
</configuration>
自动配置服务创建
我们希望可以在starter启动时就自动通过application.xml的配置信息来生成一个有关本地核心通信的配置类,这个配置类将贯穿于后续的通信。
GatewayAutoConfig.java
package com.zshunbao.gateway.assist.config;
import com.zshunbao.gateway.assist.application.GatewayApplication;
import com.zshunbao.gateway.assist.domain.service.RegisterGatewayService;
import com.zshunbao.gateway.core.session.defaults.DefaultGatewaySessionFactory;
import com.zshunbao.gateway.core.socket.GatewaySocketServer;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* @program: api-gateway-assist
* @ClassName GatewayAutoConfig
* @description: 网关配置服务,这里利用了Java的 SPI机制进行bean创建
* @author: zs宝
* @create: 2025-08-21 15:30
* @Version 1.0
**/
@Configuration
@EnableConfigurationProperties(GatewayServiceProperties.class)
public class GatewayAutoConfig {
private Logger logger = LoggerFactory.getLogger(GatewayAutoConfig.class);
@Bean
public RegisterGatewayService registerGatewayService(){
return new RegisterGatewayService();
}
@Bean
public GatewayApplication gatewayApplication(GatewayServiceProperties properties,RegisterGatewayService registerGatewayService, com.zshunbao.gateway.core.session.Configuration configuration){
return new GatewayApplication(properties,registerGatewayService,configuration);
}
/**
* 创建网关配置对象 Configuration 用于贯穿整个网关核心通信
* @return
*/
@Bean
public com.zshunbao.gateway.core.session.Configuration gatewayCoreConfiguration(GatewayServiceProperties properties){
com.zshunbao.gateway.core.session.Configuration configuration=new com.zshunbao.gateway.core.session.Configuration();
//配置好相关的网管地址和端口号
String[] split = properties.getGatewayAddress().split(":");
configuration.setHostName(split[0].trim());
configuration.setPort(Integer.parseInt(split[1].trim()));
return configuration;
}
/**
* 初始化网关服务,创建服务端channel对象,方便获取和控制网关操作
* @param configuration
* @return
*/
@Bean
public Channel initGateway(com.zshunbao.gateway.core.session.Configuration configuration) throws ExecutionException, InterruptedException {
//1、基于配置构建网络会话工厂
DefaultGatewaySessionFactory gatewaySessionFactory=new DefaultGatewaySessionFactory(configuration);
//2、创建启动网关核心通信的服务
GatewaySocketServer server=new GatewaySocketServer(configuration,gatewaySessionFactory);
Future<Channel> future= Executors.newFixedThreadPool(2).submit(server);
Channel channel = future.get();
if (null == channel) throw new RuntimeException("api gateway core netty server start error channel is null");
while (!channel.isActive()){
logger.info("api gateway core netty server gateway start Ing ...");
Thread.sleep(500);
}
logger.info("api gateway core netty server gateway start Done! {}", channel.localAddress());
return channel;
}
}
主要增加了gatewayCoreConfiguration方法,用这个方法创建了配置类bean,并初步给了网关通信模块的服务地址和端口等信息
同时增加了initGateway方法,这个方法将在starter启动时自动创建一个网关通信的服务端,并返回对应的channel bean。这个函数的信息其实就是我们上一章的测试内容修改而来。
映射信息加载
在上一章的测试中我们验证到我们的网关通信组件启动完成前后我们都可以添加映射接口,也就是当有新的接口注册上来以后,也可以随时映射到网关中。因此我们将在从所有bean加载完毕后,触发事件检测,从网关注册中心拿到对应的远程服务系统信息,我们将从这个信息中提取出相关的远程服务引用缓存需要的信息,以及相关HTTPStatement映射信息
GatewayApplication.java
package com.zshunbao.gateway.assist.application;
import com.alibaba.fastjson.JSON;
import com.zshunbao.gateway.assist.config.GatewayServiceProperties;
import com.zshunbao.gateway.assist.domain.model.aggregates.ApplicationSystemRichInfo;
import com.zshunbao.gateway.assist.domain.model.vo.ApplicationInterfaceMethodVO;
import com.zshunbao.gateway.assist.domain.model.vo.ApplicationInterfaceVO;
import com.zshunbao.gateway.assist.domain.model.vo.ApplicationSystemVO;
import com.zshunbao.gateway.assist.domain.service.RegisterGatewayService;
import com.zshunbao.gateway.core.mapping.HttpCommandType;
import com.zshunbao.gateway.core.mapping.HttpStatement;
import com.zshunbao.gateway.core.session.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import java.util.List;
/**
* @program: api-gateway-assist
* @ClassName GatewayApplication
* @description: 网关应用;与 Spring 链接,调用网关注册和接口拉取
* @author: zs宝
* @create: 2025-08-21 15:26
* @Version 1.0
**/
public class GatewayApplication implements ApplicationListener<ContextRefreshedEvent> {
private Logger logger = LoggerFactory.getLogger(GatewayApplication.class);
private GatewayServiceProperties properties;
private RegisterGatewayService registerGatewayService;
private Configuration configuration;
public GatewayApplication(GatewayServiceProperties properties, RegisterGatewayService registerGatewayService, Configuration configuration) {
this.properties = properties;
this.registerGatewayService = registerGatewayService;
this.configuration = configuration;
}
//当所有容器加载完毕时,即监听到了上下文事件更新,然后调用注册方法,向网关注册中心发起注册
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
// 1. 注册网关服务;每一个用于转换 HTTP 协议泛化调用到 RPC 接口的网关都是一个算力,这些算力需要注册网关配置中心
registerGatewayService.doRegister(properties.getAddress(),
properties.getGroupId(),
properties.getGatewayId(),
properties.getGatewayName(),
properties.getGatewayAddress());
//2、从注册中心拉取映射信息配置
ApplicationSystemRichInfo applicationSystemRichInfo = registerGatewayService.pullApplicationSystemRichInfo(properties.getAddress(), properties.getGatewayId());
//System.out.println(JSON.toJSONString(applicationSystemRichInfo));
//现在我们就要从这些信息中提取出来,网关核心通信需要的映射信息,包括构建Dubbo引用缓存需要的内容,以及HTTPStatement
List<ApplicationSystemVO> systemList = applicationSystemRichInfo.getApplicationSystemVOList();
for(ApplicationSystemVO systemVO:systemList){
List<ApplicationInterfaceVO> interfaceList = systemVO.getInterfaceList();
for(ApplicationInterfaceVO interfaceVO:interfaceList){
//配置中加入可以构建Dubbo 引用缓存的内容
configuration.registryConfig(systemVO.getSystemId(), systemVO.getSystemRegistry(),interfaceVO.getInterfaceId(),interfaceVO.getInterfaceVersion());
//接下来获得HttpStatement的信息,并加入网关通信配置中去
List<ApplicationInterfaceMethodVO> methodList = interfaceVO.getMethodList();
for(ApplicationInterfaceMethodVO methodVO:methodList){
HttpStatement httpStatement=new HttpStatement(
methodVO.getSystemId(),
methodVO.getInterfaceId(),
methodVO.getMethodId(),
methodVO.getParameterType(),
methodVO.getUri(),
HttpCommandType.valueOf(methodVO.getHttpCommandType()),
methodVO.isAuth()
);
configuration.addMapper(httpStatement);
logger.info("网关服务注册映射 系统:{} 接口:{} 方法:{}", systemVO.getSystemId(), interfaceVO.getInterfaceId(), methodVO.getMethodId());
}
}
}
}
}
其中主要就是在15章节的基础上,进行了拉取到的配置信息的使用,将这些信息做提取,让网关核心通信组件的配置类进行引用缓存的使用,以及映射信息的添加。
其余修改
最后还要更新网关注册中心的数据库表信息api-gateway-asssist-03.sql
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for application_interface
-- ----------------------------
DROP TABLE IF EXISTS `application_interface`;
CREATE TABLE `application_interface` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`system_id` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '系统标识',
`interface_id` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '接口标识',
`interface_name` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '接口名称',
`interface_version` varchar(16) COLLATE utf8_bin DEFAULT NULL COMMENT '接口版本',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx` (`system_id`,`interface_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Records of application_interface
-- ----------------------------
BEGIN;
INSERT INTO `application_interface` VALUES (1, 'api-gateway-test', 'cn.bugstack.gateway.rpc.IActivityBooth', '活动接口', '1.0.0', '2022-11-13 13:13:00', '2022-11-13 13:13:00');
COMMIT;
-- ----------------------------
-- Table structure for application_interface_method
-- ----------------------------
DROP TABLE IF EXISTS `application_interface_method`;
CREATE TABLE `application_interface_method` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`system_id` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '系统标识',
`interface_id` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '接口标识',
`method_id` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '方法标识',
`method_name` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '方法名称',
`parameter_type` varchar(256) COLLATE utf8_bin DEFAULT NULL COMMENT '参数类型;(RPC 限定单参数注册);new String[]{"java.lang.String"}、new String[]{"cn.bugstack.gateway.rpc.dto.XReq"}',
`uri` varchar(126) COLLATE utf8_bin DEFAULT NULL COMMENT '网关接口',
`http_command_type` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '接口类型;GET、POST、PUT、DELETE',
`auth` int(4) DEFAULT NULL COMMENT 'true = 1是、false = 0否',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx` (`system_id`,`interface_id`,`method_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Records of application_interface_method
-- ----------------------------
BEGIN;
INSERT INTO `application_interface_method` VALUES (1, 'api-gateway-test', 'cn.bugstack.gateway.rpc.IActivityBooth', 'sayHi', '测试方法', 'java.lang.String', '/wg/activity/sayHi', 'GET', 0, '2022-11-13 13:16:52', '2022-11-13 13:16:52');
INSERT INTO `application_interface_method` VALUES (2, 'api-gateway-test', 'cn.bugstack.gateway.rpc.IActivityBooth', 'insert', '插入方法', 'cn.bugstack.gateway.rpc.dto.XReq', '/wg/activity/insert', 'POST', 1, '2022-11-13 13:16:52', '2022-11-13 13:16:52');
COMMIT;
-- ----------------------------
-- Table structure for application_system
-- ----------------------------
DROP TABLE IF EXISTS `application_system`;
CREATE TABLE `application_system` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`system_id` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '系统标识',
`system_name` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '系统名称',
`system_type` varchar(4) COLLATE utf8_bin DEFAULT NULL COMMENT '系统类型;RPC、HTTP',
`system_registry` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '注册中心',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_systemId` (`system_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Records of application_system
-- ----------------------------
BEGIN;
INSERT INTO `application_system` VALUES (1, 'lottery-api', '抽奖API系统', 'RPC', 'zookeeper://127.0.0.1:2181', '2022-11-13 13:10:03', '2022-11-13 13:10:03');
INSERT INTO `application_system` VALUES (3, 'api-gateway-test', '网关测试系统', 'RPC', 'zookeeper://127.0.0.1:2181', '2022-11-13 13:12:54', '2022-11-13 13:12:54');
COMMIT;
-- ----------------------------
-- Table structure for gateway_distribution
-- ----------------------------
DROP TABLE IF EXISTS `gateway_distribution`;
CREATE TABLE `gateway_distribution` (
`id` int(11) NOT NULL COMMENT '自增主键',
`group_id` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '分组标识',
`gateway_id` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '网关标识',
`system_id` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '系统标识',
`system_name` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '系统名称',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Records of gateway_distribution
-- ----------------------------
BEGIN;
INSERT INTO `gateway_distribution` VALUES (1, '10001', 'api-gateway-g4', 'api-gateway-test', '测试工程', '2022-11-26 13:13:00', '2022-11-26 13:13:00');
COMMIT;
-- ----------------------------
-- Table structure for gateway_server
-- ----------------------------
DROP TABLE IF EXISTS `gateway_server`;
CREATE TABLE `gateway_server` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`group_id` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '分组标识',
`group_name` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '分组名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Records of gateway_server
-- ----------------------------
BEGIN;
INSERT INTO `gateway_server` VALUES (1, '10001', '缺省的');
COMMIT;
-- ----------------------------
-- Table structure for gateway_server_detail
-- ----------------------------
DROP TABLE IF EXISTS `gateway_server_detail`;
CREATE TABLE `gateway_server_detail` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`group_id` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '分组标识',
`gateway_id` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '网关标识',
`gateway_name` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '网关名称',
`gateway_address` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '网关地址:127.0.0.1',
`status` varchar(4) COLLATE utf8_bin DEFAULT NULL COMMENT '服务状态:0不可用、1可使用',
`create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_gateway` (`gateway_id`,`gateway_address`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Records of gateway_server_detail
-- ----------------------------
BEGIN;
INSERT INTO `gateway_server_detail` VALUES (13, '10001', 'api-gateway-g1', '电商支付网关', '127.0.0.196', '1', '2022-11-06 15:22:11', '2022-11-06 15:22:11');
INSERT INTO `gateway_server_detail` VALUES (14, '10001', 'api-gateway-g2', '电商支付网关', '127.0.0.197', '1', '2022-11-06 15:22:11', '2022-11-06 15:22:11');
INSERT INTO `gateway_server_detail` VALUES (15, '10001', 'api-gateway-g3', '电商配送网关', '127.0.0.198', '1', '2022-11-06 15:23:19', '2022-11-06 15:23:19');
INSERT INTO `gateway_server_detail` VALUES (16, '10001', 'api-gateway-g4', '电商配送网关', '127.0.0.1:7397', '1', '2022-12-03 15:36:19', '2022-12-03 15:36:19');
COMMIT;
-- ----------------------------
-- Table structure for http_statement
-- ----------------------------
DROP TABLE IF EXISTS `http_statement`;
CREATE TABLE `http_statement` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`application` varchar(128) COLLATE utf8_bin NOT NULL COMMENT '应用名称',
`interface_name` varchar(256) COLLATE utf8_bin NOT NULL COMMENT '服务接口;RPC、其他',
`method_name` varchar(128) COLLATE utf8_bin NOT NULL COMMENT ' 服务方法;RPC#method',
`parameter_type` varchar(256) COLLATE utf8_bin NOT NULL COMMENT '参数类型(RPC 限定单参数注册);new String[]{"java.lang.String"}、new String[]{"cn.bugstack.gateway.rpc.dto.XReq"}',
`uri` varchar(128) COLLATE utf8_bin NOT NULL COMMENT '网关接口',
`http_command_type` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '接口类型;GET、POST、PUT、DELETE',
`auth` int(4) NOT NULL DEFAULT '0' COMMENT 'true = 1是、false = 0否',
`create_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- ----------------------------
-- Records of http_statement
-- ----------------------------
BEGIN;
INSERT INTO `http_statement` VALUES (1, 'api-gateway-test', 'cn.bugstack.gateway.rpc.IActivityBooth', 'sayHi', 'java.lang.String', '/wg/activity/sayHi', 'GET', 0, '2022-10-22 15:30:00', '2022-10-22 15:30:00');
INSERT INTO `http_statement` VALUES (2, 'api-gateway-test', 'cn.bugstack.gateway.rpc.IActivityBooth', 'insert', 'cn.bugstack.gateway.rpc.dto.XReq', '/wg/activity/insert', 'POST', 1, '2022-10-22 15:30:00', '2022-10-22 15:30:00');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
测试
测试内容如第15章一样在api-gateway-assist-00中进行,但是对于其中的pom依赖要改为
<dependency>
<groupId>com.zshunbao.gateway</groupId>
<artifactId>api-gateway-assist-03</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
配置application.yml
server:
port: 8002
api-gateway:
address: http://localhost:8001 # 注册中心;从这里获取接口信息以及完成注册网关操作
groupId: 10001 # 网关分组;每一个网关通信组件都分配一个对应的分组
gatewayId: api-gateway-g4 # 网关标识;
gatewayName: 电商配送网关 # 网关名称
gatewayAddress: 127.0.0.1:7399 # 网关服务;网关的通信服务Netty启动时使用IP和端口
注意其中的端口信息,后续测试链接的端口不要写错了
启动zookeeper,api-gateway-test-provider ,api-gateway-center 。
最后启动 api-gateway-assist-00,同时用api-gateway-core-09 的 ShiroTest 生成 token 用于测试接口
打开ApiPost,进行测试
api-gateway-assist控制台