Spring、Infinispan 和 JGroups - 以编程方式配置

Spring, Infinispan and JGroups - configuration programmatically

我正在使用 Spring 4.3、Infinispan 9.11 和 JGroups 4.0.6。对于 JGroups,我使用 xml 配置,其中我有:

<TCPPING async_discovery="true"
         initial_hosts="${jgroups.tcpping.initial_hosts: HOSTS}"
(...)

假设我想在 xml 中保留配置,但是,我需要应用另一个 (yml) 配置文件中的主机列表。一种方法可能是从 Java 读取 yml 属性(我有那部分)并以某种方式将它们设置为 JGroups 配置。

这是我目前尝试过的方法:

EmbeddedCacheManager cacheManager = new DefaultCacheManager(
            GlobalConfigurationBuilder.defaultClusteredBuilder()
                    .transport()
                    .nodeName(nodeName)
                    .addProperty(JGroupsTransport.CONFIGURATION_FILE, "tcp.xml")
                    .addProperty(JGroupsTransport.CONFIGURATION_STRING, "jgroups.tcpping.initial_hosts: HOSTS")
                    .build(),
            new ConfigurationBuilder()
                    ...
                    .build()
    );

但是,配置字符串不起作用。

更新。另一次尝试:

JGroupsTransport transport = (JGroupsTransport)(cacheManager.getCacheManagerConfiguration().transport().transport());
    TCPPING ping = transport.getChannel().getProtocolStack().findProtocol(TCPPING.class);
    ping.setPortRange(1);
    ping.setInitialHosts(Arrays.asList(new IpAddress("HOST1:PORT1"), new IpAddress("HOST2:PORT2")));

这似乎也不起作用。

如果您有 JGroups JChannel,您可以像这样获取 TCPPING:channel.getProtocolStack().findProtocol(TCPPING.class) 然后调用 setter 以在其上设置 initial_hosts。

在深入 Infinispan 内部结构之前,让我先试试简单的方法。

你知道应用程序启动时的所有主机吗?如果是这样,您可以使用环境变量(或系统 属性)来注入主机列表。只需执行 java myApp -Djgroups.tcpping.initial_hosts=host1...

另一种方法是像您一样深入研究 Infinispan 的内部结构。唯一的问题是您的实现做得太晚了(此时 JGroups 通道已经初始化)。所以你需要注入一个视图(可能使用 INJECT_VIEW 协议,参见 manual

正如 Bela Ban 和 Altanis 指出的那样,问题是 Infinispan 在我能够修改传输属性之前调用了 JChannel.connect()。不过我找到了解决方法:

public class JGroupsChannelLookupImpl implements JGroupsChannelLookup {

    @Override
    public JChannel getJGroupsChannel(Properties p) {
        JChannel channel = null;
        try {
            channel = new JChannel("tcp.xml");
            TCPPING ping = channel.getProtocolStack().findProtocol(TCPPING.class);
            ping.setInitialHosts(Arrays.asList(HOST1, HOST2, HOST3, ...));
        }
        catch (Exception ex) {
            // do sth with the ex
        }
        Objects.requireNonNull(channel);
        return channel;
    }

(...)

}

然后在创建 DefaultCacheManager 时,不是直接从 xml 加载配置,而是加载通道查找:

new DefaultCacheManager(
            GlobalConfigurationBuilder.defaultClusteredBuilder()
                    .transport()
                    .nodeName(nodeName)
                    .addProperty(JGroupsTransport.CHANNEL_LOOKUP, JGroupsChannelLookupImpl.class.getName())
                    .build(),
           (...)

按预期工作!