动态更改 JNDI 提供程序
Posted
技术标签:
【中文标题】动态更改 JNDI 提供程序【英文标题】:Change JNDI Provider Dynamically 【发布时间】:2012-11-08 06:49:29 【问题描述】:我在同一台机器上有两台 HornetQ (2.2.14) 独立服务器(实时备份服务器);考虑这种情况:
-
实时服务器崩溃,备份服务器现已启动。
客户端 A(不知道 Live 服务器已崩溃)想要连接到 Live 服务器(它应该使用 Live 服务器 JNDI 提供程序查找其 Connection Factory )。
客户端 A 找不到实时服务器 JNDI 提供者,因此它应该连接到备份服务器(它应该使用 备份服务器 JNDI 提供者查找其连接工厂)。
我如何动态地为客户端 A 更改 JNDI 提供程序(更改 URL)? JNDI 故障转移有什么办法吗?
我有一个 spring 集成应用程序,它是我的 applicationContext.xml:
<!-- Default JndiTemplate -->
<bean id="defaultJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<prop key="java.naming.factory.url.pkgs">org.jboss.naming:org.jnp.interfaces</prop>
<prop key="java.naming.provider.url">jnp://localhost:1099</prop>
</props>
</property>
</bean>
<!-- Backup JndiTemplate -->
<bean id="backupJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<prop key="java.naming.factory.url.pkgs">org.jboss.naming:org.jnp.interfaces</prop>
<prop key="java.naming.provider.url">jnp://localhost:2099</prop>
</props>
</property>
</bean>
<!-- Destinations -->
<bean id="defaultDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="defaultJndiTemplate" />
<property name="jndiName" value="/queue/exampleQueue" />
</bean>
<!-- ConnectionFactories -->
<bean id="defaultConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="defaultJndiTemplate" />
<property name="jndiName" value="/ConnectionFactory" />
</bean>
<!-- JMS Template -->
<bean name="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="defaultConnectionFactory" />
<property name="sessionTransacted" value="true" />
</bean>
<!-- Message Producer -->
<bean name="messageSender" class="messaging.producer.MessageSender">
<property name="jmsTemplate" ref="jmsTemplate" />
<property name="destination" ref="defaultDestination" />
</bean>
更新: 我可以通过以下方式在我的应用程序中处理从当前实时服务器查找连接工厂: 对于每条消息,
-
检查可用的 JNDI 提供程序(来自当前的实时服务器)
查找连接工厂
发送消息
类似这样的东西(它来自我的 MessageSender 类):
//init initialContexts for live and backup servers
public init() throws NamingException, CommunicationException
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
environment.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
environment.put(Context.PROVIDER_URL, "jnp://localhost:1099");
initialContext_live = new InitialContext(environment);
environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
environment.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
environment.put(Context.PROVIDER_URL, "jnp://localhost:2099");
initialContext_backup = new InitialContext(environment);
jmsTemplate = new JmsTemplate();
//Sending message to toQueue
public void send(final AbstractMessage message, String toQueue) throws NamingException
Destination destination;
try
connectionFactory = (ConnectionFactory)initialContext_live.lookup("/ConnectionFactory");
jmsTemplate.setConnectionFactory(connectionFactory);
destination = (Destination) initialContext_live.lookup(toQueue);
System.out.print("[to-live]-");
catch(Exception e) //live server is down
connectionFactory = (ConnectionFactory)initialContext_backup.lookup("/ConnectionFactory");
jmsTemplate.setConnectionFactory(connectionFactory);
destination = (Destination) initialContext_backup.lookup(toQueue);
System.out.print("[to-backup]-");
jmsTemplate.send(destination, new MessageCreator()
@Override
public Message createMessage(Session session) throws JMSException
ObjectMessage objMessage = session.createObjectMessage(message);
return objMessage;
);
System.out.println("[MessageSender] Message sent.");
但它非常耗时(大约在两秒内发送一条消息)!!!
【问题讨论】:
【参考方案1】:我在这里发现了两件事
首先你设置一个全局标志并设置 if else 条件
flag=true;
if(flag)
try
connectionFactory = (ConnectionFactory)initialContext_live.lookup("/ConnectionFactory");
jmsTemplate.setConnectionFactory(connectionFactory);
destination = (Destination) initialContext_live.lookup(toQueue);
System.out.print("[to-live]-");
else
connectionFactory = (ConnectionFactory)initialContext_backup.lookup("/ConnectionFactory");
jmsTemplate.setConnectionFactory(connectionFactory);
destination = (Destination) initialContext_backup.lookup(toQueue);
System.out.print("[to-backup]-");
catch(Exception e) //live server is down
flag=false;
connectionFactory = (ConnectionFactory)initialContext_backup.lookup("/ConnectionFactory");
jmsTemplate.setConnectionFactory(connectionFactory);
destination = (Destination) initialContext_backup.lookup(toQueue);
System.out.print("[to-backup]-");
所以这里它不会检查实时服务器的代码,如果它之间的某种连接丢失将直接连接到备份服务器
如果您的实时服务器已启动,您可以将 flag 设置为 true。
catch 块中的第二件事而不是异常声明它是针对特定异常的。它也会影响性能。
【讨论】:
谢谢,更好了!但我想知道是否有 JNDI 故障转移的方法! 不,一旦我们知道实时服务器已启动,我们需要将标志设置为 true。以上是关于动态更改 JNDI 提供程序的主要内容,如果未能解决你的问题,请参考以下文章
如何动态更改 Mongoose 提供程序中的集合或数据库的名称,Nestjs?
如何使用 Nestjs 中的请求范围提供程序动态更改数据库连接?