Java 传输侦听器和ActiveMq重启
我开发了JMS应用程序,现在我想添加支持代理重启的特性。我有动态主题,我应该在连接恢复后重新创建它们。我也有可能知道经纪人什么时候下跌,什么时候回来。 因此,我尝试使用ActiveMQ故障切换协议实现此功能。我实现了TransportListener,并在方法“transportInterrupted”中调用完全断开连接,如Java 传输侦听器和ActiveMq重启,java,jms,activemq,race-condition,Java,Jms,Activemq,Race Condition,我开发了JMS应用程序,现在我想添加支持代理重启的特性。我有动态主题,我应该在连接恢复后重新创建它们。我也有可能知道经纪人什么时候下跌,什么时候回来。 因此,我尝试使用ActiveMQ故障切换协议实现此功能。我实现了TransportListener,并在方法“transportInterrupted”中调用完全断开连接,如 public void disconnect() throws JMSException { System.out.println("!!!!!!!DISCON
public void disconnect() throws JMSException {
System.out.println("!!!!!!!DISCONNECTING!!!!!!!!");
consumer.close();
session.close();
session = null;
messageProducer.close();
messageProducer = null;
connection = null;
connected = false;
System.out.println("!!!!!!!DISCONNECTED!!!!!!!!");
}
在此之后,我的应用程序挂起,就像比赛条件一样。如果我关闭()only producer并将连接设置为null,一切都可以,但如果我尝试关闭consumer,它只在1/N的情况下起作用。我写的测试证明了这一点。我认为关闭消费者是个问题,但我没有发现我做错了什么
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class FastFailProducer {
volatile boolean connected = false;
private ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("failover:(tcp://localhost:61616)?timeout=5000");;
private static FailoverListener failoverListener;
private Connection connection;
private Session session;
private Queue queue;
private MessageProducer messageProducer;
private MessageConsumer consumer;
private String something;
public void init() throws JMSException {
System.out.println("!!!!!!!CONNECTING!!!!!!!!");
connection = factory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
connection.start();
((ActiveMQConnection) connection).addTransportListener(failoverListener);
queue = session.createQueue("TEST");
messageProducer = session.createProducer(queue);
consumer = session.createConsumer(queue);
System.out.println("!!!!!!!CONNECTING COMPLETE!!!!!!!!");
connected = true;
}
public void disconnect() throws JMSException {
System.out.println("!!!!!!!DISCONNECTING!!!!!!!!");
consumer.close();
session.close();
session = null;
messageProducer.close();
messageProducer = null;
connection = null;
connected = false;
System.out.println("!!!!!!!DISCONNECTED!!!!!!!!");
}
public void run() throws Exception {
// send messages
for (int i = 0; i < 1000; i++) {
if (connected) {
if (session != null & messageProducer != null & queue != null) {
// send a message
messageProducer.send(session.createTextMessage(i + " message"));
System.out.println("Sent message " + i);
}
} else {
// execute your backup logic
System.out.println("Message " + i + " not sent");
}
Thread.sleep(1000);
}
messageProducer.close();
session.close();
connection.close();
System.exit(0);
}
public static void main(String[] args) throws Exception {
FastFailProducer failoverProducer = new FastFailProducer();
failoverProducer.something = "asdfasdf";
failoverListener = new FailoverListener(failoverProducer);
failoverProducer.init();
failoverProducer.setConnected(true);
failoverProducer.run();
}
public boolean isConnected() {
return connected;
}
public void setConnected(boolean connected) {
this.connected = connected;
}
}
我认为您没有抓住使用故障转移协议的要点。如果使用故障转移,则无需关闭连接及其相关资源,因为故障转移传输将负责恢复客户端上的所有内容,就像代理停止之前一样。在事件方法中关闭连接肯定会锁定,因为您不需要这样做。如果希望在代理离开时关闭所有内容,请不要使用故障转移,而是在JMS异常侦听器事件挂钩上侦听 哦,谢谢你。有时候我觉得实现这个功能太过分了。但这是否意味着我应该自己实现重连逻辑?我将在我的连接上添加一些ExceptionListener,然后当我收到某种IOException或JMSException时,我必须尝试重新连接到代理?非常有趣的是,为什么这个示例挂起试图关闭消费者或会话。我没有关闭连接,我只是关闭消费者/生产者和会话…事情可能会挂起,因为触发事件的传输处于重新连接逻辑中,并且持有内部锁,如果您执行类似于关闭消费者的操作,可能会导致死锁。TransportListener只是应用程序的通知机制,您的控制逻辑应该从其他线程触发。根据我从您的初始帖子中收集到的信息,您应该需要在代理宕机时执行任何工作,故障转移传输将重新建立客户端连接和资源,就像代理宕机时一样。
import java.io.IOException;
import javax.jms.JMSException;
import org.apache.activemq.transport.TransportListener;
public class FailoverListener implements TransportListener {
private FastFailProducer failProducer;
public FailoverListener(FastFailProducer failProducer) {
super();
this.failProducer = failProducer;
}
@Override
public void onCommand(Object arg0) {
}
@Override
public void onException(IOException arg0) {
}
@Override
public void transportInterupted() {
try {
failProducer.disconnect();
} catch (JMSException e) {
e.printStackTrace();
}
}
@Override
public void transportResumed() {
System.out.println("!!!!!!!TRANSPORT RESUMED!!!!!!!!");
if (!failProducer.isConnected()) {
try {
failProducer.init();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}