详情介绍
2025/9/7大约 4 分钟
详情介绍
组件工作逻辑
服务注册流程
心跳维持流程
文件详细说明
1. GatewayRegisterService
路径: top.codelong.findsdk.service
作用: 服务注册核心处理器,实现BeanPostProcessor接口
关键逻辑:
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
logger.debug("开始处理Bean: {}", beanName);
// 1. 检查ApiInterface注解
ApiInterface apiInterface = bean.getClass().getAnnotation(ApiInterface.class);
if (null == apiInterface) {
logger.trace("Bean {} 未包含ApiInterface注解,跳过处理", beanName);
return bean;
}
logger.info("发现API接口类: {}", bean.getClass().getName());
// 2. 验证接口实现
Class<?>[] interfaces = bean.getClass().getInterfaces();
if (interfaces.length != 1) {
logger.error("接口类必须实现且仅实现一个接口");
throw new RuntimeException("接口类只能有一个接口");
}
// 3. 构建接口注册信息
InterfaceRegisterVO registerVO = new InterfaceRegisterVO();
Class<?> interfaceClass = interfaces[0];
registerVO.setInterfaceName(interfaceClass.getName());
registerVO.setSafeKey(config.getSafeKey());
registerVO.setSafeSecret(config.getSafeSecret());
// 4. 设置服务地址
String serverPort = environment.getProperty("server.port", "8080");
String localIp = "localhost";
try {
localIp = InetAddress.getLocalHost().getHostAddress();
logger.debug("获取本地IP地址: {}", localIp);
} catch (Exception e) {
logger.warn("获取本地IP地址失败,使用默认localhost", e);
}
registerVO.setServerUrl(localIp + ":" + serverPort);
logger.info("服务地址: {}", registerVO.getServerUrl());
// 5. 处理方法信息
List<MethodSaveDomain> methodList = new ArrayList<>();
Method[] methods = bean.getClass().getMethods();
for (Method method : methods) {
ApiMethod apiProducerMethod = method.getAnnotation(ApiMethod.class);
if (apiProducerMethod == null) {
logger.trace("方法 {} 未包含ApiMethod注解,跳过处理", method.getName());
continue;
}
logger.debug("处理方法: {}", method.getName());
MethodSaveDomain saveDomain = buildMethodMetadata(method, apiProducerMethod);
methodList.add(saveDomain);
// 6. 非HTTP方法需要暴露Dubbo服务
if (apiProducerMethod.isHttp() == 0) {
logger.info("暴露Dubbo服务: {}", method.getName());
exposeMethodService(bean, interfaceClass, saveDomain);
}
}
registerVO.setMethods(methodList);
// 7. 注册接口到网关中心
logger.info("开始注册接口到网关中心...");
register(registerVO);
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}2. InterfaceRegisterVO
路径: top.codelong.findsdk.vo
作用: 封装接口注册信息
数据结构:
/**
* 接口注册 ReqVO
*/
public class InterfaceRegisterVO {
private String serverUrl; // 服务器地址
private String safeKey; // 安全密钥
private String safeSecret; // 安全凭证
private String interfaceName; // 接口全限定名
private List<MethodSaveDomain> methods; // 方法列表
// getter和setter方法
}3. ApiMethod
路径: top.codelong.findsdk.annotation
作用: 定义方法元数据注解
属性说明:
/**
* 自定义方法注解
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ApiMethod {
int isHttp() default 0; // 是否是HTTP接口 (1:是, 0:否)
HttpTypeEnum httpType() default HttpTypeEnum.GET; // HTTP方法类型
String url() default ""; // HTTP接口URL
int isAuth() default 0; // 是否需要认证 (1:是, 0:否)
}4. GatewaySDKAutoConfig
路径: top.codelong.findsdk.config
作用: 组件自动配置入口
关键配置:
@Configuration
@EnableConfigurationProperties(GatewayServerConfig.class)
@ConditionalOnProperty(
prefix = "api-gateway-sdk",
name = "enabled",
havingValue = "true",
matchIfMissing = true
)
public class GatewaySDKAutoConfig {
@Bean
public GatewayRegisterService gatewayRegisterService() {
return new GatewayRegisterService();
}
}5. GatewayServerConfig
路径: top.codelong.findsdk.config
作用: 网关服务配置属性
配置项:
/**
* 网关服务配置
*/
@ConfigurationProperties(prefix = "gateway-server")
public class GatewayServerConfig {
private String serverName; // 服务名称
private String centerAddr; // 网关中心地址
private String safeKey; // 安全密钥
private String safeSecret; // 安全凭证
// getter和setter方法
}6. HeartbeatService
路径: top.codelong.findsdk.service
作用: 心跳维持服务
核心逻辑:
public void heartbeat() {
logger.debug("开始发送心跳请求...");
// 1. 准备心跳参数
String safeKey = config.getSafeKey();
String serverPort = environment.getProperty("server.port", "8080");
String localIp = "localhost";
try {
localIp = InetAddress.getLocalHost().getHostAddress();
logger.debug("获取本地IP地址成功: {}", localIp);
} catch (Exception e) {
logger.warn("获取本地IP地址失败,使用默认localhost", e);
}
String localAddr = localIp + ":" + serverPort;
logger.info("当前服务地址: {}", localAddr);
// 2. 构建请求URL
String centerAddr = config.getCenterAddr();
String fullUrl = centerAddr + "/gateway-server-detail/keep-alive";
logger.debug("网关中心地址: {}", fullUrl);
// 3. 准备请求参数
Map<String, Object> param = new HashMap<>();
param.put("safeKey", safeKey);
param.put("addr", localAddr);
logger.trace("心跳请求参数: {}", param);
// 4. 发送HTTP请求
HttpRequest request = HttpUtil.createRequest(Method.PUT, fullUrl);
request.header("Content-Type", "application/json");
request.body(JSON.toJSONString(param));
try {
HttpResponse response = request.execute();
// 注意:实际代码中未记录成功日志,仅捕获异常
} catch (Exception e) {
logger.error("心跳维持失败", e);
}
}7. RedisConfig
路径: top.codelong.findsdk.config
作用: 配置Redis消息监听
关键配置:
@Configuration
public class RedisConfig {
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(
RedisConnectionFactory factory,
RedisMessageListener listener) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(factory);
container.addMessageListener(listener, new ChannelTopic("heartBeat"));
return container;
}
}文件协同工作
- 启动阶段:
- Spring Boot加载
META-INF/spring.factories中的自动配置 GatewaySDKAutoConfig创建GatewayRegisterServiceBean
- Spring Boot加载
- 服务注册阶段:
GatewayRegisterService扫描带有@ApiInterface的Bean- 使用
ApiMethod解析方法元数据 - 对于Dubbo接口,使用
DubboConfig的配置进行服务暴露 - 构造
InterfaceRegisterVO和MethodSaveDomain - 发送注册请求到
GatewayServerConfig.centerAddr
- 运行阶段:
RedisConfig创建消息监听容器RedisMessageListener监听"heartBeat"频道- 触发
HeartbeatService发送心跳到网关中心
- 配置管理:
- 所有配置通过
GatewayServerConfig统一管理 - Dubbo基础配置通过
DubboConfig提供
- 所有配置通过
注意事项
接口实现要求:
// 只能实现一个接口 public class UserServiceImpl implements UserService { // 其他接口会导致异常 }Dubbo服务暴露:
// 每个方法独立group暴露 serviceConfig.setGroup("method-group-" + saveDomain.getMethodName());心跳触发:
// 需要网关中心向Redis发送"heartBeat"消息 // 触发心跳维持机制服务配置:
gateway-server: serverName: test-provider center-addr: 127.0.0.1:18080 safeKey: safeKey safeSecret: safeSecretHTTP接口:
@ApiMethod(isHttp=1, url="/custom/path") // 需要自行实现HTTP接口