Java WeakReferences = 理解问题(使用 HornetQ JMS 实现)?
下面的代码不起作用:
原因:
我假设我找到了原因: http://community.jboss.org/thread/150988 =>这篇文章说HornetQ使用弱引用。
我的问题: 为什么代码不运行? (我的代码运行时的实现略有不同,但代码重复失败)。我唯一的猜测是 以下参考文献:
private Connection connection = null;
private Session session = null;
private MessageProducer producer = null;
不被视为强参考文献吗? (这导致垃圾收集器删除对象......但是它们不是强引用吗?
或者代码是否存在另一个问题(正如所说,如果我将所有内容复制到一个方法中,代码运行良好。但是如果我使用下面的单例方法,代码不起作用...)另一个假设是它可能与 ThreadLocal 的东西有关,但我只使用单个线程...
代码不起作用(精简) :
public class JMSMessageSenderTest {
private static final Logger logger = Logger.getLogger(JMSMessageSenderTest.class);
private static JMSMessageSenderTest instance;
private Connection connection = null;
private Session session = null;
private MessageProducer producer = null;
private JMSMessageSenderTest() {
super();
}
public static JMSMessageSenderTest getInstance() throws JMSException {
if (instance==null) {
synchronized(JMSMessageSenderTest.class) {
if (instance==null) {
JMSMessageSenderTest instanceTmp = new JMSMessageSenderTest();
instanceTmp.initializeJMSConnectionFactory();
instance = instanceTmp;
}
} }
return instance;
}
private void createConnectionSessionQueueProducer() throws Exception {
try {
Queue queue = HornetQJMSClient.createQueue("testQueue");
connection = initializeJMSConnectionFactory();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(queue);
connection.start();
} catch (Exception e) {
cleanupAfterError();
throw e;
}
}
private void cleanupAfterError() {
if (connection != null){
try{
connection.close();
}catch(JMSException jmse) {
logger.error("Closing JMS Connection Failed",jmse);
}
}
session = null;
producer = null;
}
public synchronized void sendRequest(String url) throws Exception {
if (connection==null) {
createConnectionSessionQueueProducer();
}
try {
//HERE THE EXCEPTION IS THROWN, at least when debugging
TextMessage textMessage = session.createTextMessage(url);
producer.send(textMessage);
} catch (Exception e) {
cleanupAfterError();
throw e;
}
}
private Connection initializeJMSConnectionFactory() throws JMSException{
Configuration configuration = ConfigurationFactory.getConfiguration(null, null);
Map<String, Object> connectionParams = new HashMap<String, Object>();
connectionParams.put(org.hornetq.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME, 5445);
connectionParams.put(org.hornetq.core.remoting.impl.netty.TransportConstants.HOST_PROP_NAME, "localhost");
TransportConfiguration transportConfiguration = new TransportConfiguration(NettyConnectorFactory.class.getName(), connectionParams);
ConnectionFactory connectionFactory = (ConnectionFactory) HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transportConfiguration);
// return connectionFactory.createConnection(login, password);
return connectionFactory.createConnection();
}
/**
* Orderly shutdown of all resources.
*/
public void shutdown() {
cleanupAfterError();
}
}
TestCode 运行代码上面
JMSMessageSenderTest jmsMessageSender = JMSMessageSenderTest.getInstance();
jmsMessageSender.sendRequest("www.example.com)");
jmsMessageSender.shutdown();
给出以下错误:
I'm closing a JMS connection you left open. Please make sure you close all JMS connections explicitly before letting them go out of scope!
The JMS connection you didn't close was created here:
java.lang.Exception
at org.hornetq.jms.client.HornetQConnection.<init>(HornetQConnection.java:152)
at org.hornetq.jms.client.HornetQConnectionFactory.createConnectionInternal(HornetQConnectionFactory.java:662)
at org.hornetq.jms.client.HornetQConnectionFactory.createConnection(HornetQConnectionFactory.java:121)
解决方案:
1.)您还必须保留对 ConnectionFactory 的引用(请参阅下面 Clebert 的答案)
private ConnectionFactory factory = null;
2.)并且此代码包含一个严重的隐藏错误(不太容易发现): 我在构造函数和 createConnectionSessionQueueProducer() 方法中初始化了连接。因此,它将覆盖旧值并且(因为它是需要关闭的资源)将导致陈旧的连接,然后 HornetQ 将关闭该连接并抛出错误。
非常非常感谢!马库斯
The code below does NOT work:
Cause:
I assume I tracked down the cause to:
http://community.jboss.org/thread/150988
=> This article says that HornetQ uses Weak References.
My Question:
Why does the code not run? (I have this code running with a slight different implementation, but the code blow fails repeatedly). My only guess is, that the
following references:
private Connection connection = null;
private Session session = null;
private MessageProducer producer = null;
are not regarded as strong references? (And this leads to the fact that the garbage collector removes the objects... But way arent they strong references?
Or is there another problem with the code (as said the code runs fine if I copy everything into one single method. But if I use the Singleton approach below the code does not work...) Another assumption was that it might have to do with ThreadLocal stuff, but I am using only a single thread...
The Code not working (stripped down):
public class JMSMessageSenderTest {
private static final Logger logger = Logger.getLogger(JMSMessageSenderTest.class);
private static JMSMessageSenderTest instance;
private Connection connection = null;
private Session session = null;
private MessageProducer producer = null;
private JMSMessageSenderTest() {
super();
}
public static JMSMessageSenderTest getInstance() throws JMSException {
if (instance==null) {
synchronized(JMSMessageSenderTest.class) {
if (instance==null) {
JMSMessageSenderTest instanceTmp = new JMSMessageSenderTest();
instanceTmp.initializeJMSConnectionFactory();
instance = instanceTmp;
}
} }
return instance;
}
private void createConnectionSessionQueueProducer() throws Exception {
try {
Queue queue = HornetQJMSClient.createQueue("testQueue");
connection = initializeJMSConnectionFactory();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(queue);
connection.start();
} catch (Exception e) {
cleanupAfterError();
throw e;
}
}
private void cleanupAfterError() {
if (connection != null){
try{
connection.close();
}catch(JMSException jmse) {
logger.error("Closing JMS Connection Failed",jmse);
}
}
session = null;
producer = null;
}
public synchronized void sendRequest(String url) throws Exception {
if (connection==null) {
createConnectionSessionQueueProducer();
}
try {
//HERE THE EXCEPTION IS THROWN, at least when debugging
TextMessage textMessage = session.createTextMessage(url);
producer.send(textMessage);
} catch (Exception e) {
cleanupAfterError();
throw e;
}
}
private Connection initializeJMSConnectionFactory() throws JMSException{
Configuration configuration = ConfigurationFactory.getConfiguration(null, null);
Map<String, Object> connectionParams = new HashMap<String, Object>();
connectionParams.put(org.hornetq.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME, 5445);
connectionParams.put(org.hornetq.core.remoting.impl.netty.TransportConstants.HOST_PROP_NAME, "localhost");
TransportConfiguration transportConfiguration = new TransportConfiguration(NettyConnectorFactory.class.getName(), connectionParams);
ConnectionFactory connectionFactory = (ConnectionFactory) HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transportConfiguration);
// return connectionFactory.createConnection(login, password);
return connectionFactory.createConnection();
}
/**
* Orderly shutdown of all resources.
*/
public void shutdown() {
cleanupAfterError();
}
}
TestCode to run the code above
JMSMessageSenderTest jmsMessageSender = JMSMessageSenderTest.getInstance();
jmsMessageSender.sendRequest("www.example.com)");
jmsMessageSender.shutdown();
Gives the following error:
I'm closing a JMS connection you left open. Please make sure you close all JMS connections explicitly before letting them go out of scope!
The JMS connection you didn't close was created here:
java.lang.Exception
at org.hornetq.jms.client.HornetQConnection.<init>(HornetQConnection.java:152)
at org.hornetq.jms.client.HornetQConnectionFactory.createConnectionInternal(HornetQConnectionFactory.java:662)
at org.hornetq.jms.client.HornetQConnectionFactory.createConnection(HornetQConnectionFactory.java:121)
Solution:
1.) You also have to Keep a reference to the ConnectionFactory (see the answer from Clebert below)
private ConnectionFactory factory = null;
2.) AND this code contains a severe hidden bug (that is not so easy to spot):
I initialized the Connection in the Constructor as well as in the createConnectionSessionQueueProducer() method. It will therefore override the old value and (as it is a Ressource that needs to be closed) will lead to a stale connection that HornetQ then will close and will then throw the error.
Thanks very very much! Markus
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当连接工厂被释放时,HornetQ将关闭连接工厂。
您需要保留连接工厂的引用。
HornetQ will close the connection factory when the connection factory is released.
You need to hold a reference for the connection factory.
我也有类似的问题。但它不应该崩溃。你的实现看起来不错。但唯一的问题是您没有关闭 JMS 连接,而该连接又被 hornetQ gc 关闭。
代码可能存在问题的一件事是您仅在异常之后调用 cleanupAfterError() 。在发布消息并且 JMS 连接处于空闲状态后,您也应该调用相同的方法。由于您只是打开一个连接来发布消息,然后除非发生异常,否则不会关闭该连接,因此 Hornetq GC 会在抛出此错误时找到该对象并将其删除。
如果我错过了什么,请告诉我
I also have similar issues. But it is not supposed to crash . Your implementation looks good. But only thing is that you are not closing the JMS connection , which in turn is getting closed by the hornetQ gc.
One thing probably wrong with the code is that you are calling cleanupAfterError() only after an exception. You should call the same method also after you have posted a message and a JMS connection is lying idle . Since you are just opening a connection to post a message and then not closing that connection unless an exception happens , Hornetq GC is finding that object and removing it while throwing this error.
Let me know if I missed something