Tiy*_*iya 0 jms objectoutputstream
这是我的客户端代码:
\n\n公共类 ABCServlet 扩展 HttpServlet {
\n\nprotected void doGet(HttpServletRequest request,\n HttpServletResponse response){\n//do blah blah\nString msg = null;\n\njava.io.OutputStream os = response.getOutputStream();\njava.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(os);\noos.writeObject(msg);\nmsg = null;\noos.flush();\noos.close();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我不知道如何使用上面的代码我的监听器被启动 -
\n\npublic class ABCListener implements MessageListener {\n\n@Override\npublic void onMessage(Message arg0) {\n AbstractJDBCFacade fa\xc3\xa7ade = null;\n try{\n fa\xc3\xa7ade = something;\n throw new UserException();\n }catch(UserException ex){\n log.error("ABC Exception " + ex);\n }\nRun Code Online (Sandbox Code Playgroud)\n\n配置 :
\n\n<bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">....\n\n<bean id="jmsQueue" class="org.springframework.jndi.JndiObjectFactoryBean">\n\n<bean id="listenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer102">\nRun Code Online (Sandbox Code Playgroud)\n\n我有 3 个问题:\n1. 如果不显式地将其放入队列,如何调用侦听器?\n2. 当 onMessage 方法抛出 UserException 时,我想将消息传递给客户端,而不是记录日志。我怎样才能做到这一点 ?\n3. 为什么有人会使用 JndiObjectFactoryBean 而不是 ActiveMQ...
\nJMS 从设计上就应该是异步的、单向的。即使使用消费者的接收方法的“同步”jms也会在内部转变为创建一个新的临时队列。在这里我们谈到第二点,即它的单向性。JMS 队列应该是单向的,这就是为什么它被称为点对点 ( http://www.enterpriseintegrationpatterns.com/patterns/messaging/PointToPointChannel.html )。当然,从技术上讲,通过一些舞蹈,您将设法实现您想要的目标,但这是不好的做法,由于您需要过滤,还会导致性能下降。
为了让这件事快速工作,最好的方法是拥有一个逻辑接收器(当然,您可以对一个接收器使用并发消费者,但这应该是一个逻辑消费者,不需要过滤消息)。
- 如果不显式地将其放入队列,如何调用侦听器?
仅当消息到达队列时才会调用侦听器。这是让它按预期工作的唯一方法。
一般来说,消息消费模型有两种类型:推送(也称为事件驱动消费)和轮询。在使用推送模型的情况下,所有侦听器(根据规范观察者模式)都会在代理中的某个位置注册,然后,当代理在某个队列中接收到新消息时,它会执行侦听器的方法。另一方面,在轮询模型中,消费者负责自己接收消息。因此,每隔一段时间,它就会到达代理并检查队列中是否有新消息。
推送模型:http://www.enterpriseintegrationpatterns.com/patterns/messaging/EventDrivenConsumer.html
民意调查模型:http://www.enterpriseintegrationpatterns.com/patterns/messaging/PollingConsumer.html
- When onMessage method throws UserException, instead of logging I want to pass the message to the client. How can I do that ?
Thats a very bad practice. Of course technically you can achieve it with dirty tricks but thats not the right way of using jms. When onMessage throws the exception then message wont be taken from the queue (of course if u did not reconfigured acknowledge mods or used another tricks). So the best way of solving your probem fmpv is to use redelivery limit on message and a dead letter queue(http://www.enterpriseintegrationpatterns.com/patterns/messaging/DeadLetterChannel.html). If system was not able to process the message after some attempts (redelivery limit shows exactly this) then broker remove message from the queue and send it to a so-called dead letter queue where all failed (from the point of broker) messages are stored. And then client can read that queue and decide what to do with message.
In amq: http://activemq.apache.org/message-redelivery-and-dlq-handling.html
If you want to use so-called "synchronous" features in JMS and really there is no way of using dead letter queue or smth like that then actually you can use consumer.recieve method on the client. But in this case you should send response on every message. In case of success you can send one message and in case of failure error messages. And so a client will be able to understand what is going on. But i dont think that you need such a huge overhead cause actually you need only failure messages. Also in this case you will have to take care about appropriate receive timeouts.
- Why would someone use JndiObjectFactoryBean instead of ActiveMQ...
That's cause you are using Spring and there are additional features especially for spring.
PS: 1. For consuming:
How can I send a message using just this piece of code? Don't I need to put this on a queue? java.io.OutputStream os = response.getOutputStream(); java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(os); oos.writeObject(msg); For receiving smth like this: `
<bean id="connectionFactory" class="org.springframework.
jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="baseJNDITemplate"/>
<property name="jndiName"
value="weblogic.jms.ConnectionFactory"/>
</bean>
<bean id="queue" class="org.springframework.
jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="baseJNDITemplate"/>
<property name="jndiName" value="#{properties.queueName}"/>
</bean>
<bean id="messageListenerContainer"
class="org.springframework.jms.listener.
DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="queue"/>
<property name="messageListener" ref="messageListener"/>
<property name="sessionTransacted" value="true"/>
</bean>
<bean id="messageListener" class="com.example.ABCListener"/>
Run Code Online (Sandbox Code Playgroud)
And then simply all logic for message processing will be in the listener.
For sending smth like this in config:
<bean id="jmsQueueTemplate"
class="org.springframework.
jms.core.JmsTemplate">
<property name="connectionFactory">
<ref bean="jmsConnectionFactory"/>
</property>
<property name="destinationResolver">
<ref bean="jmsDestResolver"/>
</property>
...
</bean>
<bean id="jmsDestResolver"
class=" org.springframework.jms.support.destination.
JndiDestinationResolver"/>
<bean id="jmsConnectionFactory"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jms/myCF"/>
<property name="lookupOnStartup" value="false"/>
<property name="cache" value="true"/>
<property name="proxyInterface" value="amq con fact here"/>
</bean>
Run Code Online (Sandbox Code Playgroud)
and in code simply use jmsTemplate.send(queue, messageCreator) method:
@Autowired
ConnectionFactory connectionFactory;
@Test(enabled = false)
public void testJmsSend(final String msg) throws Exception {
JmsTemplate template = new JmsTemplate(connectionFactory);
template.send("test_queue", new MessageCreator() {
@Override
public Message createMessage(Session session)
throws JMSException {
return session.createTextMessage(msg);
}
});
}
Run Code Online (Sandbox Code Playgroud)
- I believe Dead channel comes in picture only when the message is not properly received by the receiver. In my case, the receiver received it and processed it, however while processing it failed with some exception. I want to let the sender know that there was a exception and the message did not process successfully. I can do this using a response queue but I don't want to do that, can the receiver receive a message from the sender on the same queue ? How?
Dead letter channel is a kind of error handling for message processing also. If message processing had failed then after the limit end it got transferred there. It is not actually only for transport issues but also for processing issues. If the message processing got failed with exception then message will stay in the queue and wont be acked by default. So what we should do with this message? For example if it failed due to our database error or smth like this? We should initiate error-handling process, notify assurance systems and stakeholders, collect all necessary info and preserve the message. Due to this kind of queues, which was create d exactly for that, it is much easier. And then customer support team will investigate error queue for further analysis of what has happened. Also we have monitoring tools for notifications and statistics collection on such errors. After understanding what has happened message got removed from the queue and archived.
After processing a message, the consumer is responsible for deleting the message. If the consumer doesn't delete the message, for example because because it crashed while processing the message, the message becomes visible again after the message's Visibility Timeout expires. Each time this happens, the message's receive count is increased.
When this count reaches a configured limit, the message is placed in a designated Dead Letter Queue.
http://www.enterpriseintegrationpatterns.com/patterns/messaging/DeadLetterChannel.html
I can do this using a response queue but I don't want to do that, can the receiver receive a message from the sender on the same queue ? How?
For you it will look like it's the same queue but internally new temporary queue will be created. To achieve that you should use jms request\reply message pattern. More here: http://activemq.apache.org/how-should-i-implement-request-response-with-jms.html
唯一仍然让我困惑的是:如果我希望我的 JMS 侦听器(接收器)侦听队列,那么我的发送者也应该实现 JMS 并连接到同一队列并发送消息。但是在我支持的 ABCListener 应用程序中没有任何将发送者配置到队列的配置。发送者所做的只是 3 行代码: java.io.OutputStream os = response.getOutputStream(); java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(os); oos.writeObject(msg); 从字面上看,就是这样。我不知道它仍然有效!
当然,3 行带有输出流的代码除了填充 msg 字符串之外什么也不做。无论如何,要将任何 jms 消息发送到队列,您都必须使用 JMS Api 或 Spring 之类的一些库,它们通过添加附加功能来包装消息。
我编写了简单的示例以使其更加清晰。
修改了 servlet,用于使用死信队列进行异步处理(对于 dlq,您还应该创建另一个监听器 ofc)
public class AsynchronousJmsSenderServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String msg = null;
try (java.io.OutputStream os = response.getOutputStream()) {
try(java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(os)) {
oos.writeObject(msg);
}
}
sendJmsMessage(msg);
}
private void sendJmsMessage(final String msg) {
ConnectionFactory connectionFactory = null; //here get it in some way from spring
JmsTemplate template = new JmsTemplate(connectionFactory);
template.send("your_queue_name", new MessageCreator() {
@Override
public Message createMessage(Session session)
throws JMSException {
return session.createTextMessage(msg);
}
});
}
}
Run Code Online (Sandbox Code Playgroud)这是“同步”处理和状态回复消息的代码
public class SynchronousJmsSenderServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String msg = null;
try (java.io.OutputStream os = response.getOutputStream()) {
try(java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(os)) {
oos.writeObject(msg);
}
}
sendJmsMessage(msg);
}
private void sendJmsMessage(final String msg) {
ConnectionFactory connectionFactory = null; //here get it in some way from spring
JmsTemplate template = new JmsTemplate(connectionFactory);
Message reply = template.sendAndReceive("your_queue_name", new MessageCreator() {
@Override
public Message createMessage(Session session)
throws JMSException {
return session.createTextMessage(msg);
}
});
if(reply instanceof TextMessage) {
try {
String status = ((TextMessage) reply).getText();
//do error handling if status is error
} catch (JMSException ex) {
throw new RuntimeException("Unable to get status message", ex);
}
} else {
throw new RuntimeException("Only text messages are supported");
}
}
}
public class SynchronousJmsMessageListener implements SessionAwareMessageListener {
@Override
public void onMessage(Message request, Session session) throws JMSException {
try {
//do some processing
sendReply(request, session, "OK");
} catch (Exception ex) {
sendReply(request, session, "Error: " + ex.toString());
}
}
private void sendReply(Message request, Session session, String status) {
try {
TextMessage reply = null; //for example you can use ActiveMQTextMessage here
reply.setJMSCorrelationID(request.getJMSCorrelationID());
reply.setText(status);
MessageProducer producer = session.createProducer(reply.getJMSReplyTo());
producer.send(reply);
} catch (JMSException exception) {
throw new RuntimeException("Unable to send reply", exception);
}
}
}
Run Code Online (Sandbox Code Playgroud)您将需要 Spring 5 在 jmsTemplate 上具有 sendAndReceive 方法。或者您将必须手动完成所有这些操作。
PS1:请告诉我这是否有效
| 归档时间: |
|
| 查看次数: |
4256 次 |
| 最近记录: |