如何在运行时正确修改JPOS Channel-Adapter的端口?
运行时动态配置JPOS Channel-Adapter的规范实现
问题背景
需要通过JSON POST请求接收用户指定的端口、ISO格式等参数,动态调整JPOS的Channel-Adapter连接配置。现有实现能完成端口切换并正常发送交易,但原端口仍持续尝试重连,不符合JPOS规范做法。
相关代码与配置如下:
Spring接收请求接口
@PostMapping(value = "/message", consumes = DEFAULT_CONTENT_TYPE, produces = DEFAULT_CONTENT_TYPE) void postIsoMessage( @RequestHeader(value = HEADER_CORRELATION_ID) String correlationId, @RequestBody JsonMessage requestMessage) throws Exception { // 处理JSON请求逻辑 ... }
用户请求JSON示例
{ "config": { "keyset": "KEYSET_1", "pinblockFmt": "01 - ISO 0 Format", "acq": { "format": "VISANET", "portNumber": 9405 }, "iss": { "format": "ISO4", "portNumber": 9488 } } }
原Channel-Adapter/Mux XML配置
<channel-adaptor name="iss-channel" class="org.jpos.q2.iso.ChannelAdaptor" logger="Q2"> <channel class="org.jpos.iso.channel.CSChannel" packager="org.jpos.iso.packager.GenericPackager" logger="Q2"> <property name="packager-config" value="src/main/resources/iso4.xml" /> <property name="host" value="10.999.99.99" /> <property name="port" value="9999" /> <property name="timeout" value="300000" /> </channel> <in>iss-channel-send</in> <out>iss-channel-receive</out> <reconnect-delay>10000</reconnect-delay> </channel-adaptor> <mux class="org.jpos.q2.iso.QMUX" logger="Q2" name="iss-mux" realm="acq-realm"> <in>iss-channel-receive</in> <out>iss-channel-send</out> <ready>iss-channel.ready</ready> <request-listener class="AutoResponder"></request-listener> </mux>
当前非规范实现
Q2 q2 = new Q2("src/main/java/deploy"); q2.start(); Thread.sleep(3000L); QMUX qmux = NameRegistrar.getIfExists("mux.acq-mux"); ChannelAdaptor channel = NameRegistrar.getIfExists("iss-channel"); if (channel == null) System.out.println("channel doesn't exist"); else { channel.setPort(9488); channel.startService(); // 从9999切换到9488端口 NameRegistrar.register("iss-channel",channel); Thread.sleep(3000L); } try { if (qmux.isConnected()) { ISOMsg m = new ISOMsg(); m.setMTI("0100"); m.set(2, "4999999999999999"); // ... 其他字段设置 ISOMsg response = qmux.request(m, 5000);
当前方案的问题
日志显示新端口9488连接成功并正常交易,但原端口9999仍在尝试重连:
<log realm="channel/10.999.99.99:9488" at="2023-03-02T08:38:04.930" lifespan="3ms"> <connect> Try 0 10.999.99.99:9488 </connect> </log> <log realm="channel" at="2023-03-02T08:38:05.171" lifespan="2051ms"> <connect> Try 0 10.999.99.99:9999 Connection refused: connect Unable to connect </connect> </log>
原因是未停止原Channel-Adapter服务就直接修改参数重启,原服务的重连线程仍在后台运行,导致同时存在两个连接尝试逻辑。
规范实现方式
JPOS推荐通过动态部署服务的方式实现运行时配置调整,核心是先停止原有服务,再根据请求参数重新配置并启动新服务:
步骤1:停止原有Channel-Adapter服务
ChannelAdaptor oldChannel = NameRegistrar.getIfExists("iss-channel"); if (oldChannel != null) { oldChannel.stopService(); NameRegistrar.unregister("iss-channel"); // 等待服务完全停止 Thread.sleep(1000L); }
步骤2:动态构建新的Channel-Adapter配置
可以通过API直接构建Channel和ChannelAdaptor实例,无需依赖XML文件:
// 构建CSChannel CSChannel newChannel = new CSChannel(); newChannel.setLogger(Q2.getQ2().getLogger(), "iss-channel"); newChannel.setPackager(new GenericPackager("src/main/resources/iso4.xml")); newChannel.setHost("10.999.99.99"); // 从请求中获取端口 newChannel.setPort(requestMessage.getConfig().getIss().getPortNumber()); newChannel.setTimeout(300000); // 构建ChannelAdaptor ChannelAdaptor newChannelAdaptor = new ChannelAdaptor(); newChannelAdaptor.setName("iss-channel"); newChannelAdaptor.setChannel(newChannel); newChannelAdaptor.setInQueue("iss-channel-send"); newChannelAdaptor.setOutQueue("iss-channel-receive"); newChannelAdaptor.setReconnectDelay(10000); newChannelAdaptor.setLogger(Q2.getQ2().getLogger(), "iss-channel");
步骤3:注册并启动新服务
// 注册到NameRegistrar NameRegistrar.register("iss-channel", newChannelAdaptor); // 启动服务 newChannelAdaptor.startService(); // 等待服务就绪 Thread.sleep(3000L);
可选:动态生成XML部署文件
如果偏好XML配置方式,可以生成临时XML文件,通过Q2的Deployer部署:
String configXml = String.format(""" <channel-adaptor name="iss-channel" class="org.jpos.q2.iso.ChannelAdaptor" logger="Q2"> <channel class="org.jpos.iso.channel.CSChannel" packager="org.jpos.iso.packager.GenericPackager" logger="Q2"> <property name="packager-config" value="src/main/resources/iso4.xml" /> <property name="host" value="10.999.99.99" /> <property name="port" value="%d" /> <property name="timeout" value="300000" /> </channel> <in>iss-channel-send</in> <out>iss-channel-receive</out> <reconnect-delay>10000</reconnect-delay> </channel-adaptor> """, requestMessage.getConfig().getIss().getPortNumber()); // 写入临时文件 File tempConfig = File.createTempFile("iss-channel", ".xml"); Files.writeString(tempConfig.toPath(), configXml); // 部署到Q2 Q2.getQ2().getDeployer().deploy(tempConfig.getAbsolutePath());
疑问解答
当前iss-mux是否同时连接两个端口?
不会。Mux关联的是指定的队列(iss-channel-send/iss-channel-receive),只有当前活跃的Channel-Adapter会向这些队列发送/接收消息。但原端口的重连线程仍在后台运行,会占用系统资源,且可能产生无效日志。原端口重连会引发问题吗?
会。长期运行会导致不必要的线程占用、网络连接尝试,甚至可能因为频繁重连触发目标主机的防火墙限制。必须停止原服务后再启动新配置,才能彻底终止原重连逻辑。
内容的提问来源于stack exchange,提问作者tytyty
相关产品推荐
相关产品推荐

