十六章 网络通信配置提取

提取 Netty 通信服务配置信息,包括:IP、端口、线程数等,到会话的 Configuration 配置类中进行统一的维护和管理,便于外部调用方向内部传递信息。

设计

对于第16章内容的处理,主要来自于在第17章开发的api-gateway-assist-03 网关通信助手组件,对于网关通信服务的启动,可以指定配置下 Netty 服务的IP地址和端口信息。

之前这部分配置是写死在 GatewaySocketServer 类中的,所以要对这部分内容进行处理。此外由于我们需要对 api-gateway-core 进行组件打包 Jar 给 api-gateway-assist 引入使用,那么还需要优化下 POM 配置,避免每次打包都做对 test 进行操作

这里还有一个细节点,api-gateway-assist 引入 api-gateway-core 以后,如果希望把这个 Jar 包打入到 api-gateway-assist 中。那么api-gateway-core 的包结构最好是有一个区分的。但目前是 cn.ray.gateway 之后就是各个分层功能了,所以我们调整为 cn.ray.gateway.core 的结构来处理。

16-设计

实现

提取配置

这里我们要把 GatewaySocketServer 类中的一些配置信息,包括;服务启动IP、服务端口、线程数进行提取。

16-实现

配置内容提取后,就是放到 Configuration 中进行统一维护。这里不要再增加其他的配置文件或者说通过构造入参的方式进行处理,因为这样你会失去对一个配置的统一管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package cn.ray.gateway.core.session;

import cn.ray.gateway.core.authorization.IAuth;
import cn.ray.gateway.core.authorization.auth.AuthService;
import cn.ray.gateway.core.bind.MapperRegistry;
import cn.ray.gateway.core.bind.IGenericReference;
import cn.ray.gateway.core.datasource.Connection;
import cn.ray.gateway.core.executor.SimpleExecutor;
import cn.ray.gateway.core.mapping.HttpStatement;
import cn.ray.gateway.core.executor.Executor;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.rpc.service.GenericService;

import java.util.HashMap;
import java.util.Map;

/**
* @author Ray
* @date 2023/5/12 21:47
* @description 会话生命周期配置项
*/
public class Configuration {

/** 网关 Netty 服务地址 */
private String hostName = "127.0.0.1";

/** 网关 Netty 服务端口 */
private int port = 7397;

/** 网关 Netty 服务线程数配置 */
private int bossNThreads = 1;
private int workNThreads = 4;

// ... 省略部分代码

在 Configuration 类中统一维护网关的一些配置信息。

禁止打包测试内容

1
2
3
4
5
6
7
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>

【skipTests&maven.test.skip】

  • skipTests=true:install打包时不执行单元测试用例,但是会编译测试用例类生成的class文件到target/test-classes
  • maven.test.skip=true:则表示不执行测试用例,也不编译测试用例类

测试

ApiTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package cn.ray.gateway.test;

import cn.ray.gateway.core.mapping.HttpRequestType;
import cn.ray.gateway.core.mapping.HttpStatement;
import cn.ray.gateway.core.session.Configuration;
import cn.ray.gateway.core.session.defaults.DefaultGatewaySessionFactory;
import cn.ray.gateway.core.socket.GatewaySocketServer;
import io.netty.channel.Channel;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
* @author Ray
* @date 2023/5/11 16:26
* @description
*/
public class ApiTest {

private final Logger logger = LoggerFactory.getLogger(ApiTest.class);

@Test
public void test_GenericReference() throws InterruptedException, ExecutionException {
// 1. 创建配置信息加载注册
Configuration configuration = new Configuration();
configuration.setHostName("127.0.0.1");
configuration.setPort(7037);

// 2. 基于配置构建会话工厂
DefaultGatewaySessionFactory gatewaySessionFactory = new DefaultGatewaySessionFactory(configuration);

// 3. 创建启动网关网络服务
GatewaySocketServer server = new GatewaySocketServer(configuration, gatewaySessionFactory);

Future<Channel> future = Executors.newFixedThreadPool(2).submit(server);
Channel channel = future.get();

if (null == channel) throw new RuntimeException("netty server start error channel is null");

while (!channel.isActive()) {
logger.info("netty server gateway start Ing ...");
Thread.sleep(500);
}
logger.info("netty server gateway start Done! {}", channel.localAddress());

// 4. 注册接口
configuration.registerConfig("api-gateway-test","zookeeper://127.0.0.1:2181","cn.ray.gateway.rpc.IActivityBooth", "1.0.0");

HttpStatement httpStatement01 = new HttpStatement(
"api-gateway-test",
"cn.ray.gateway.rpc.IActivityBooth",
"sayHi",
"/wg/activity/sayHi",
HttpRequestType.GET,
"java.lang.String",
false);

HttpStatement httpStatement02 = new HttpStatement(
"api-gateway-test",
"cn.ray.gateway.rpc.IActivityBooth",
"insert",
"/wg/activity/insert",
HttpRequestType.POST,
"cn.ray.gateway.rpc.dto.XReq",
true);

configuration.addMapper(httpStatement01);
configuration.addMapper(httpStatement02);

Thread.sleep(Long.MAX_VALUE);
}
}

测试结果

GET

16-测试-1

POST

16-测试-2

思考

在更新后的代码中,接口的注册(configuration.registerConfig)是在Netty服务器启动之后进行的。然而,这些操作的顺序不会影响接口注册的成功。

之所以仍然可以成功,是因为接口的注册过程并不依赖于Netty服务器本身。它与服务器的状态无关。registerConfig 方法负责将接口信息注册到 Configuration 对象中。它设置了服务器处理已注册接口的传入请求所需的必要配置数据。

而Netty服务器则负责实际处理请求和与客户端通信。它不依赖于接口注册的具体顺序。只要在服务器开始处理请求之前提供了必要的配置信息,它就能够处理已注册接口的请求。

因此,即使在Netty服务器启动后进行注册,仍然可以成功,因为服务器在请求处理过程中需要时才会访问已注册的接口信息。