业务流程
在上一节中,我们实现了网关注册中心的对外的网关聚合配置信息的查询接口,有了这个接口,我们的网关算力节点(api-gateway-core)就可以通过这个接口获得映射信息。但是这个映射信息我们在之前几章的流程梳理过,不能直接由算力节点拉取,而应该由对它进行包装的starter进行拉取,这个过程就像starter自动帮算力节点进行注册一样。所以本章节的主要内容就是,接着开发api-gateway-assist
这个包装算力节点的starter,让其可以自动从网关注册中心拉取映射信息。后续章节我们再处理映射操作,因为映射还需要把网关核心算力引入到助手组件中进行包装使用。如下图(图片来自于xfg)
业务实现
项目结构如下
这里的开发其实和第13章的开发几乎一模一样,只是由于我们接收到的信息是从第14章来的聚合对象,因此要将14章的聚合对象和VO引入进来。同时我们更新了项目结构,创建了domain层,将之前的服务移入其中
添加向网关注册中心发起拉取映射信息请求的接口RegisterGatewayService#pullApplicationSystemRichInfo
,几乎和之前的自动注册一样,只是请求的网关注册中心的接口变了,那么入参也就变了,返回的结果也变了。
package com.zshunbao.gateway.assist.domain.service;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.zshunbao.gateway.assist.GatewayException;
import com.zshunbao.gateway.assist.common.Result;
import com.zshunbao.gateway.assist.domain.model.aggregates.ApplicationSystemRichInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
* @program: api-gateway-assist
* @ClassName RegisterGatewayService
* @description: 网关注册服务
* @author: zs宝
* @create: 2025-08-21 15:17
* @Version 1.0
**/
public class RegisterGatewayService {
private Logger logger = LoggerFactory.getLogger(RegisterGatewayService.class);
/**
* 进行向api-gateway-center网关注册中心发起注册的服务
* @param address 注册中心地址
* @param groupId api-gateway-core分组ID
* @param gatewayId 网关ID
* @param gatewayName 网关名称
* @param gatewayAddress 网关地址
*/
public void doRegister(String address, String groupId, String gatewayId, String gatewayName, String gatewayAddress) {
//封装请求参数
Map<String,Object> paramMap=new HashMap<>();
paramMap.put("groupId", groupId);
paramMap.put("gatewayId", gatewayId);
paramMap.put("gatewayName", gatewayName);
paramMap.put("gatewayAddress", gatewayAddress);
//调用hutool工具包发送请求
String resultStr = HttpUtil.post(address+"/wg/admin/config/registerGateway", paramMap, 1200);
//将返回结果用自定义的结果类包装
Result result = JSON.parseObject(resultStr, Result.class);
logger.info("向网关中心注册网关算力服务 gatewayId:{} gatewayName:{} gatewayAddress:{} 注册结果:{}", gatewayId, gatewayName, gatewayAddress, resultStr);
if(!"0000".equals(result.getCode())){
throw new GatewayException("网关服务注册异常 [gatewayId:" + gatewayId + "] 、[gatewayAddress:" + gatewayAddress + "]");
}
}
public ApplicationSystemRichInfo pullApplicationSystemRichInfo(String address, String gatewayId) {
logger.info("开始向网关注册中心拉取配置 gatewayId:{} ",gatewayId);
//封装请求参数
Map<String,Object> paramMap=new HashMap<>();
paramMap.put("gatewayId",gatewayId);
String resultStr=HttpUtil.post(address+"/wg/admin/config/queryApplicationSystemRichInfo", paramMap, 1200);
Result<ApplicationSystemRichInfo> result = JSON.parseObject(resultStr, new TypeReference<Result<ApplicationSystemRichInfo>>(){});
if (!"0000".equals(result.getCode()))
throw new GatewayException("从网关中心拉取应用服务和接口的配置信息到本地完成注册异常 [gatewayId:" + gatewayId + "]");
logger.info("向网关注册中心拉取配置成功 gatewayId:{} 配置信息 {}",gatewayId,resultStr);
return result.getData();
}
}
最后由于要让starter自动拉取,还得如之前的注册一样,添加监听事件GatewayApplication.java
.相当于添加了一个额外的扩展调用,等下个章节继续完成调用后的注册映射处理。HTTP->RPC
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.service.RegisterGatewayService;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
/**
* @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 GatewayServiceProperties properties;
private RegisterGatewayService registerGatewayService;
public GatewayApplication(GatewayServiceProperties properties, RegisterGatewayService registerGatewayService) {
this.properties = properties;
this.registerGatewayService = registerGatewayService;
}
//当所有容器加载完毕时,即监听到了上下文事件更新,然后调用注册方法,向网关注册中心发起注册
@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));
}
}
到此本节的业务逻辑上的代码已经完成,我们再补充下上节的聚合类和VO类吧
ApplicationSystemRichInfo.java
package com.zshunbao.gateway.assist.domain.model.aggregates;
import com.zshunbao.gateway.assist.domain.model.vo.ApplicationSystemVO;
import java.util.List;
/**
* @program: api-gateway-assist
* @ClassName ApplicationSystemRichInfo
* @description: 网关算力配置信息->即每个api-gateway-core的映射信息
* @author: zs宝
* @create: 2025-08-22 15:59
* @Version 1.0
**/
public class ApplicationSystemRichInfo {
/** 网关ID */
private String gatewayId;
/** 系统列表 */
private List<ApplicationSystemVO> applicationSystemVOList;
public ApplicationSystemRichInfo(String gatewayId, List<ApplicationSystemVO> applicationSystemVOList) {
this.gatewayId = gatewayId;
this.applicationSystemVOList = applicationSystemVOList;
}
public ApplicationSystemRichInfo(){
}
public String getGatewayId() {
return gatewayId;
}
public void setGatewayId(String gatewayId) {
this.gatewayId = gatewayId;
}
public List<ApplicationSystemVO> getApplicationSystemVOList() {
return applicationSystemVOList;
}
public void setApplicationSystemVOList(List<ApplicationSystemVO> applicationSystemVOList) {
this.applicationSystemVOList = applicationSystemVOList;
}
}
ApplicationSystemVO.java
package com.zshunbao.gateway.assist.domain.model.vo;
import java.util.List;
/**
* @program: api-gateway-center
* @ClassName ApplicationSystemVO
* @description: 注册系统VO
* @author: zs宝
* @create: 2025-08-20 14:29
* @Version 1.0
**/
public class ApplicationSystemVO {
/** 系统标识 */
private String systemId;
/** 系统名称 */
private String systemName;
/** 系统类型;RPC、HTTP*/
private String systemType;
/** 注册中心;zookeeper://127.0.0.1:2181*/
private String systemRegistry;
private List<ApplicationInterfaceVO> interfaceList;
public String getSystemId() {
return systemId;
}
public void setSystemId(String systemId) {
this.systemId = systemId;
}
public String getSystemName() {
return systemName;
}
public void setSystemName(String systemName) {
this.systemName = systemName;
}
public String getSystemType() {
return systemType;
}
public void setSystemType(String systemType) {
this.systemType = systemType;
}
public String getSystemRegistry() {
return systemRegistry;
}
public void setSystemRegistry(String systemRegistry) {
this.systemRegistry = systemRegistry;
}
public List<ApplicationInterfaceVO> getInterfaceList() {
return interfaceList;
}
public void setInterfaceList(List<ApplicationInterfaceVO> interfaceList) {
this.interfaceList = interfaceList;
}
}
ApplicationInterfaceVO.java
package com.zshunbao.gateway.assist.domain.model.vo;
import java.util.List;
/**
* @program: api-gateway-center
* @ClassName ApplicationInterfaceVO
* @description: 注册接口VO
* @author: zs宝
* @create: 2025-08-20 14:29
* @Version 1.0
**/
public class ApplicationInterfaceVO {
/** 系统标识 */
private String systemId;
/** 接口标识 */
private String interfaceId;
/** 接口名称 */
private String interfaceName;
/** 接口版本 */
private String interfaceVersion;
private List<ApplicationInterfaceMethodVO> methodList;
public String getSystemId() {
return systemId;
}
public void setSystemId(String systemId) {
this.systemId = systemId;
}
public String getInterfaceId() {
return interfaceId;
}
public void setInterfaceId(String interfaceId) {
this.interfaceId = interfaceId;
}
public String getInterfaceName() {
return interfaceName;
}
public void setInterfaceName(String interfaceName) {
this.interfaceName = interfaceName;
}
public String getInterfaceVersion() {
return interfaceVersion;
}
public void setInterfaceVersion(String interfaceVersion) {
this.interfaceVersion = interfaceVersion;
}
public List<ApplicationInterfaceMethodVO> getMethodList() {
return methodList;
}
public void setMethodList(List<ApplicationInterfaceMethodVO> methodList) {
this.methodList = methodList;
}
}
ApplicationInterfaceMethodVO.java
package com.zshunbao.gateway.assist.domain.model.vo;
/**
* @program: api-gateway-center
* @ClassName ApplicationInterfaceMethodVO
* @description: 注册函数VO
* @author: zs宝
* @create: 2025-08-20 14:29
* @Version 1.0
**/
public class ApplicationInterfaceMethodVO {
/** 系统标识 */
private String systemId;
/** 接口标识 */
private String interfaceId;
/** 方法标识 */
private String methodId;
/** 方法名称 */
private String methodName;
/** 参数类型(RPC 限定单参数注册);new String[]{"java.lang.String"}、new String[]{"cn.bugstack.gateway.rpc.dto.XReq"} */
private String parameterType;
/** 网关接口 */
private String uri;
/** 接口类型;GET、POST、PUT、DELETE */
private String httpCommandType;
/** 是否鉴权;true = 1是、false = 0否 */
private Integer auth;
public String getSystemId() {
return systemId;
}
public void setSystemId(String systemId) {
this.systemId = systemId;
}
public String getInterfaceId() {
return interfaceId;
}
public void setInterfaceId(String interfaceId) {
this.interfaceId = interfaceId;
}
public String getMethodId() {
return methodId;
}
public void setMethodId(String methodId) {
this.methodId = methodId;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public String getParameterType() {
return parameterType;
}
public void setParameterType(String parameterType) {
this.parameterType = parameterType;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getHttpCommandType() {
return httpCommandType;
}
public void setHttpCommandType(String httpCommandType) {
this.httpCommandType = httpCommandType;
}
public Integer getAuth() {
return auth;
}
public void setAuth(Integer auth) {
this.auth = auth;
}
}
测试
本次测试,我们新增加了 api-gateway-assist-00 的测试工程,它是一个 SpringBoot 的应用工程,用于测试 api-gateway-assist 组件实现。为什么要这么做呢?我们之前一直梳理到,我们的api-gateway-assist
是一个对于api-gateway-core
的包装,相当于一个starter,未来这个starter是要用于引入到api-gateway-engin
中去的,就像SpringBoot会引入SpringBoot starter一样,这个相当于我们专门为我们的API网关做的starter。这个starter一定是要有放在其它的项目中引入测试其功能的。
来看,这个测试项目就是一个啥功能都没有的 SpringBoot 的应用工程,但是它的pom文件中一定要引入我们的starter
package com.zshunbao.gateway.assist;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* @program: api-gateway-assist
* @ClassName Application
* @description:
* @author: zs宝
* @create: 2025-08-22 16:26
* @Version 1.0
**/
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@Configurable
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
其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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zshunbao</groupId>
<artifactId>api-gateway-assist-00</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.0</version>
</dependency>
<dependency>
<groupId>com.zshunbao</groupId>
<artifactId>api-gateway-assist-02</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<finalName>api-gateway-assist</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
其中一定要包含对我们api-gateway-assist
这个starter的引入
<dependency>
<groupId>com.zshunbao</groupId>
<artifactId>api-gateway-assist-02</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
最后,我们在我们的starter中对于注册信息的相关配置是放于配置文件中,因此这里还要配置相关的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和端口
最后先启动网关注册中心api-gateway-center
,再启动这个测试项目,在starter中打上断点,debug运行
而在网关注册中心中有
测试应用放行
最后从本章开始,我们网关项目会开始涉及到多个模块的功能开发联调测试,随着后续开发SDK等都引入后,会增加更多的内容,每个章节一定要把握好每章的核心开发功能需求是什么。