UpA*_*ght 4 java activemq-classic ejb
我有一个关于何时关闭在无状态会话bean(EJB)中创建的连接的一般问题。连接是到ActiveMQ的,它们是在Bean的构造函数中创建的。然后在一个方法中使用该连接,我想知道何时关闭该连接的适当时间/地点。
有一个单独的方法来关闭连接是否合适,类必须使用Bean来调用该方法?还是应该简单地使用该方法在方法内关闭连接?我担心我可能会关闭一个连接,然后再将其与现在关闭的连接一起使用,因为该连接是在构造函数中打开的。这是一些需要注意的代码:
@Stateless
@LocalBean
public class SendEventsBean {
private static String brokerURL = ".......";
private static transient ConnectionFactory factory;
private transient Connection connection;
private transient Session session;
private transient MessageProducer producer;
public SendEventsBean() {
factory = new ActiveMQConnectionFactory(brokerURL);
try {
connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(null);
} catch (JMSException e) {
e.printStackTrace();
}
}
public void sendEvent(String id, String description, String area) {
Destination destination;
try {
destination = session.createQueue("FWT." + "events");
TextMessage message = session.createTextMessage(id + " " + description + " " + area);
producer.send(destination, message);
} catch (JMSException e) {
e.printStackTrace();
}
}
public void close() throws JMSException {
if (connection != null) {
connection.close();
}
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我目前有一个单独的close方法,该类应该在发送事件后由bean使用该类调用。这合法吗,还是自找麻烦?我对EJB经验不足,并且愿意接受任何建议。使用@EJB批注将bean注入到调用类中。
A better approach would look something like this example (JavaEE6 JMS style) which sends an ObjectMessage to a Queue from within a stateless EJB:
@Stateless
public class SendEventsBean {
private static final Logger log = Logger.getLogger(SendEventsBean.class);
@Resource(mappedName = "jms/MyConnectionFactory")
private ConnectionFactory jmsConnectionFactory;
@Resource(mappedName = "jms/myApp/MyQueue")
private Queue queue;
public void sendEvent() {
Connection jmsConnection = null;
try {
connection = jmsConnectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(queue);
MyObj obj = new MyObj(1, "Foo");
ObjectMessage myObjMsg = session.createObjectMessage(obj);
producer.send(myObjMsg);
} catch (JMSException jmxEx) {
log.error("Couldn't send JMS message: ", jmsEx);
}finally{
if (jmsConnection != null) {
try {
jmsConnection.close();
}catch(JMSException ex) {
log.warn("Couldn't close JMSConnection: ", ex);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
JMS resources should be administered by your Application server (unless you need to use dynamic ones) and as such will be exposed to your application for @Resource injection.
Caching JMS resources in your stateless session bean is not recommended by Oracle. It is very very cheap to create a JMSConnection object as it is only a thin wrapper around the physical connection.
As such its OK not to cache it, or create and tear it down in @PostConstruct/@PreDestroymethods. In fact I've tested out the approach of leveraging the EJB lifecycle methods for this and only run into problems.
Also the Session and Producer objects are not thread safe, they need to be created once per thread. You could run into threading issues by storing/caching them in the SLSB as properties.
All these are reasons to keep it simple and leverage your resources locally in your producer method.
There are other details/considerations you will need to factor in, for example the level and type of transaction support you might need. Or the handling of 'poison messages', but with my simple example I am trying to address some of the basic issues I see with many of the answers here. Hope this helps.