Restrict execution of concurrent queue in Spring JMS - spring

Ideally after one queue completes its execution, another queue should start.
I am using Spring JMS. But at a time more than one queue able to execute by which data mismatch occurs.
So can anyone please tell how to restrict concurrent queue or unless first queue ends the 2nd queue cannot be started or all other queues are in waiting.
public class MyQueueListener implements MessageListener {
public void onMessage(Message message) {
try {
if (message instanceof ObjectMessage) {
ObjectMessage objectMessage = (ObjectMessage) message;
MyQueueObject obj= (MyQueueObject)objectMessage.getObject();
String productId = obj.getProductId();
IMyService myService;
myService.updateAllCustomerDetails(productId);
}
} catch (JMSException j) {
j.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
}
<bean id="mySenderService" class="MySenderService">
<property name="jmsTemplate" ref="myjmsTemplate" />
<property name="queue" ref="myQueueDestination" />
</bean>
<bean id="myQueueDestination" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>queue/myQueue</value>
</property>
<property name="resourceRef">
<value>true</value>
</property>
</bean>
<bean id="myQueueListener" class="MyQueueListener" ></bean>
<bean id="jmsImportContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="myQueueDestination" />
<property name="messageListener" ref="myQueueListener" />
</bean>
mySenderService.sendMessages();

Related

StatefulRetryOperationsInterceptor not working when included with TransactionInterceptor in interceptor chain

I have the below configuration in application context xml file
<bean id="methodMapWithDefaultTxAttributeSource" class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
<property name="transactionAttribute" value="PROPAGATION_REQUIRES_NEW,timeout_60"/>
</bean>
<bean id="methodMapTxInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="txManager"/>
<property name="transactionAttributeSource" ref="methodMapWithDefaultTxAttributeSource"/>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref bean="retryAdvice"/>
<idref bean="methodMapTxInterceptor"/>
</list>
</property>
<property name="beanNames">
<value>service</value>
</property>
</bean>
<bean id="txProxyTemplate"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="txManager" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRES_NEW,timeout_60</prop>
</props>
</property>
</bean>
<bean id="manager1" class="package2.Manager1">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="manager2" class="package2.Manager2">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="manager1TxProxy" parent="txProxyTemplate">
<property name="proxyTargetClass" value="true" />
<property name="target" ref="manager1" />
</bean>
<bean id="manager2TxProxy" parent="txProxyTemplate">
<property name="proxyTargetClass" value="true" />
<property name="target" ref="manager2"/>
</bean>
<bean id="retryPolicy" class="org.springframework.retry.policy.SimpleRetryPolicy">
<constructor-arg name="maxAttempts" value="3"/>
</bean>
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="retryPolicy" ref="retryPolicy"/>
</bean>
<bean id="rollbackClassifier" class="org.springframework.classify.BinaryExceptionClassifier">
<constructor-arg name="typeMap">
<util:map map-class="java.util.HashMap" key-type="java.lang.Class" value-type="java.lang.Boolean">
<entry key="java.lang.NullPointerException" value="false"/>
</util:map>
</constructor-arg>
<constructor-arg name="defaultValue" value="true"/>
<constructor-arg name="traverseCauses" value="true"/>
</bean>
<bean id="retryAdvice" class="org.springframework.retry.interceptor.StatefulRetryOperationsInterceptor">
<property name="retryOperations" ref="retryTemplate"/>
<property name="rollbackClassifier" ref="rollbackClassifier"/>
<property name="label" value="label"/>
</bean>
<bean id="service" class="package2.Service">
<property name="manager1" ref="manager1"/>
<property name="manager2" ref="manager2TxProxy"/>
</bean>
As you can see i have wrapped a interceptor chain around Service class method. The goal is add retry and transaction facility to all Service class method. I have modified the Service class below method to throw exception whenever it is called
public void executeWithException() {
manager1.execute();
throw new NullPointerException();
//manager2.execute();
}
Now in the first try, the interceptor chain has StatefulRetryOperationsInterceptor and TransactionInterceptor and before calling the Service class method transaction is created. The Service class method throws exception and it will retry.
Now in the second retry, the interceptor chain will have only StatefulRetryOperationsInterceptor and not TransactionInterceptor. I feel this is wrong. Even for second retry a new transaction has to be created. The javadoc says that. But is not happening here. The TransactionInterceptor is skipped.
Am i missing some configuration here.
Please help me out.
Screenshot of call stacktrace on first retry
Screenshot of call stacktrace on second retry
Hi Gary, I tried your example. I created my own transaction manager as shown below
public class MyTransactionManager extends AbstractPlatformTransactionManager {
private int i = 0;
#Override
protected Object doGetTransaction() throws TransactionException {
return new Object();
}
#Override
protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
System.out.println("Transaction" + i);
i = i + 1;
}
#Override
protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
}
#Override
protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
}
}
Used it in the xml file
<bean id="txManager" class="package2.MyTransactionManager"/>
Below is the console output
Transaction0
Manager1 Execute
Manager1 Execute
Manager1 Execute
Exception in thread "main"
As you see transaction doBegin method is called once printing "Transaction0". This shows new transactions are not created for every retry.
Below is the main method
public class Example2 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("example2.xml");
Service service1 = (Service)context.getBean("service");
service1.executeWithException();
}
}
When I debugged the code, TransactionInterceptor is in the chain but it is skipped on subsequent retry.
It makes no sense that the interceptor would change between calls; you must be mistaken.
It works fine for me with similar configuration as yours:
#SpringBootApplication
#ImportResource("so70609332-context.xml")
public class So70609332Application {
public static void main(String[] args) {
SpringApplication.run(So70609332Application.class, args);
}
#Bean
TransactionInterceptor txInterceptor(TransactionManager tm) {
return new TransactionInterceptor(tm, new MatchAlwaysTransactionAttributeSource());
}
#Bean
ApplicationRunner runner(Service service, MyTransactionManager tm) {
return args -> {
while (true) {
try {
callIt(service);
}
catch (IllegalStateException e) {
}
catch (Exception e) {
System.out.println(tm.begins);
break;
}
}
};
}
private void callIt(Service nt) {
try {
nt.foo();
}
catch (IllegalStateException e) {
throw e;
}
}
}
class Service {
void foo() {
System.out.println("called: " + TransactionSynchronizationManager.isActualTransactionActive());
throw new IllegalStateException();
}
}
#Component
class MyTransactionManager extends AbstractPlatformTransactionManager {
int begins;
#Override
protected Object doGetTransaction() throws TransactionException {
return new Object();
}
#Override
protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
this.begins++;
}
#Override
protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
}
#Override
protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref bean="retryAdvice" />
<idref bean="txInterceptor" />
</list>
</property>
<property name="beanNames">
<value>service</value>
</property>
</bean>
<bean id="retryTemplate"
class="org.springframework.retry.support.RetryTemplate">
</bean>
<bean id="retryAdvice"
class="org.springframework.retry.interceptor.StatefulRetryOperationsInterceptor">
<property name="retryOperations" ref="retryTemplate" />
<property name="label" value="label" />
</bean>
<bean id="service" class="com.example.demo.Service" />
</beans>
called: true
called: true
called: true
3

Using topics but not all the consumers take the message

I want to create a sender to generate message and the send it to all consumers.
I am using topic, but something is wrong, if for example I have 3 consumers, only one takes the message in a random way.
I donĀ“t know what is wrog. Here is my server configuration
<amq:broker brokerName="granicaBroker" id="broker"
persistent="false" deleteAllMessagesOnStartup="true" enableStatistics="false"
useLoggingForShutdownErrors="true">
<amq:networkConnectors>
<amq:networkConnector name="linkToBrokerB"
uri="static:(tcp://xxx.xx.xxx.xx:61617)" networkTTL="3" duplex="true" />
</amq:networkConnectors>
<amq:transportConnectors>
<amq:transportConnector
uri="nio://xxx.xx.xxx.xx:61616?jms.useAsyncSend=true?jms.useCompression=true"
disableAsyncDispatch="false" />
</amq:transportConnectors>
</amq:broker>
<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="JMS.TOPIC.NOTIFICATION" />
</bean>
<bean id="producerTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="connectionFactory"
p:defaultDestination-ref="destination" />
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="nio://xxx.xx.xxx.xx:61616" />
And my producer class(just the part to send the message)
#Autowired
protected JmsTemplate jmsTemplate;
final String text = applicationEvent.getMsg();
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
TextMessage message = session.createTextMessage(text);
return message;
}
});
My client context configuration:
p:brokerURL="nio://xxx.xx.xxx.xx:61616" />
<bean id="simpleMessageListener" class="notifications.NotifierControllerImpl"/>
<jms:listener-container container-type="default"
connection-factory="connectionFactory" acknowledge="auto">
<jms:listener destination="JMS.TOPIC.NOTIFICATION" ref="simpleMessageListener"
method="onMessage" />
</jms:listener-container>
And the java client class
public class NotifierControllerImpl implements MessageListener{
#Override
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage tm = (TextMessage)message;
System.out.println(tm.getText());
}
} catch (JMSException e) {
System.out.println(e.toString());
}
}
}
The destination needs to be a topic not a queue; use ActiveMQTopic not ActiveMQQueue.
I change jms:listener-container part
Here is the code:
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="messageListener" ref="simpleMessageListener" />
</bean>
And it works!

Spring JMS & Websphere MQ: Message is not picked up by the application

I have an application which uses spring-jms, websphere mq, websphere application server 7.
On a user interaction, I am putting a message in a Queue A. I have a Listener-A(using DefaultMessageListenerContainer in springframework) which picks up the message. That listener-A is supposed to process it and send a response to Queue A-Response. In that process, I am trying to put another message on a different Queue B for which I have a different Listener-B defined. But for some reason, after the message is put on Queue B, the Listener-B is not picking it up.
When I try to put the message manually on the Queue B, Listener-B picks the message and processes it, but when I try the above mentioned scenario, it doesn't work. Also, when I comment out the code that puts a message on Queue B in the Listener-A, then the Listener-A processes the message and sends a response back to Queue A-Response.
Any help is greatly appreciated. Thanks
Edit: Added code
Here is the spring configuration that I have
<bean id="jmsListener-Parent" abstract="true"
class="MyJmsServiceExporter">
<property name="messageTimeToLive" value="60000" />
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />
<bean id="taskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
<property name="workManagerName" value="wm/default" />
</bean>
<bean name="jmsListenerContainer-Parent"
abstract="true"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="concurrentConsumers" value="1"/>
<property name="transactionManager" ref="transactionManager" />
<property name="taskExecutor" ref="taskExecutor" />
</bean>
<bean id="FirstService-Listener" parent="jmsListener-Parent">
<property name="serviceInterface" value="FirstService" />
<property name="service" ref="FirstServiceImpl" />
<property name="messageConverter" ref="MyMessageConverter" />
</bean>
<bean id="SecondService-Listener" parent="jmsListener-Parent">
<property name="serviceInterface" value="SecondService" />
<property name="service" ref="SecondServiceImpl" />
<property name="messageConverter" ref="MyMessageConverter" />
</bean>
<bean name="FirstService-ListenerContainer"
parent="jmsListenerContainer-Parent">
<property name="destination" ref="FirstQueue-Request" />
<property name="messageListener" ref="FirstService-Listener" />
</bean>
<bean name="SecondService-ListenerContainer"
parent="jmsListenerContainer-Parent">
<property name="destination" ref="SecondQueue-Request" />
<property name="messageListener" ref="SecondService-Listener" />
</bean>
<bean id="FirstService-Client"
class="MyJmsServiceInvoker">
<property name="connectionFactory" ref="connectionFactory" />
<property name="serviceInterface" value="FirstService" />
<property name="messageConverter" ref="MyMessageConverter" />
<property name="queue" ref="FirstQueue-Request" />
<property name="responseQueue" ref="FirstQueue-Response" />
<property name="timeToLive" value="60000" />
<property name="receiveTimeout" value="60000" />
</bean>
<bean id="SecondService-Client"
class="MyJmsServiceInvoker">
<property name="connectionFactory" ref="connectionFactory" />
<property name="serviceInterface" value="SecondService" />
<property name="messageConverter" ref="MyMessageConverter" />
<property name="queue" ref="SecondQueue-Request" />
<property name="responseQueue" ref="SecondQueue-Response" />
<property name="timeToLive" value="60000" />
<property name="receiveTimeout" value="60000" />
</bean>
MyJmsServiceInvoker(extends JmsInvokerProxyFactoryBean) methods:
protected Message doExecuteRequest(
Session session,
Queue queue,
Message requestMessage)
throws JMSException {
MessageProducer producer = null;
MessageConsumer consumer = null;
Message responseMessage = null;
String correlationId = null;
String responseSelector = null;
try {
LOG.info("CmsJmsServiceInvoker::doExecuteRequest");
requestMessage.setJMSType("TEXT");
requestMessage.setJMSReplyTo(responseQueue);
requestMessage.setJMSExpiration(this.getTimeToLive());
producer = session.createProducer(queue);
if (isPersistentMessage()) {
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
} else {
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
}
producer.setTimeToLive(getTimeToLive());
LOG.info("Sending requestMessage.");
producer.send(requestMessage);
correlationId = requestMessage.getJMSMessageID();
responseSelector =
"JMSCorrelationID=\'" + correlationId + "\'";
consumer = session.createConsumer(responseQueue, responseSelector);
long timeout = getReceiveTimeout();
LOG.info("Awaiting response.");
if (timeout > 0) {
responseMessage = consumer.receive(timeout);
} else {
responseMessage = consumer.receive();
}
if (responseMessage == null) {
LOG.info("Timeout encountered.");
throw new RuntimeException("Timeout");
}
} catch (JMSSecurityException jse) {
LOG.error("SecurityException encountered.", jse);
throw new RuntimeException("JMS SecurityException, jse");
} finally {
JmsUtils.closeMessageConsumer(consumer);
JmsUtils.closeMessageProducer(producer);
}
LOG.info("Returning response Message.");
return responseMessage;
}
MyJmsServiceExporter(extends JmsInvokerServiceExporter) methods:
protected void writeRemoteInvocationResult(Message requestMessage,
Session session,
RemoteInvocationResult result)
throws JMSException {
MessageProducer producer = null;
Message response = null;
if (requestMessage.getJMSReplyTo() == null) {
LOG.debug("Async: This request will not have a "
+ "response since there is no reply queue in the "
+ "JMS header.");
return;
}
producer = session.createProducer(requestMessage.getJMSReplyTo());
try {
response = createResponseMessage(requestMessage, session,
result);
producer.setTimeToLive(getMessageTimeToLive());
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
if (persistentMessage) {
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
}
producer.send(response);
if (LOG.isDebugEnabled()) {
LOG.debug("Sending response message.");
LOG.debug(response);
}
} finally {
if (producer != null) {
JmsUtils.closeMessageProducer(producer);
}
}
}
protected Message createResponseMessage(
Message request,
Session session,
RemoteInvocationResult result)
throws JMSException {
Message response = null;
String correlation = null;
correlation = request.getJMSCorrelationID();
response = super.createResponseMessage(request, session, result);
if (correlation == null) {
correlation = request.getJMSMessageID();
}
response.setJMSCorrelationID(correlation);
response.setJMSExpiration(getMessageTimeToLive());
return response;
}
public void onMessage(Message requestMessage, Session session)
throws JMSException {
RemoteInvocationResult result = null;
try {
RemoteInvocation invocation = readRemoteInvocation(requestMessage);
if (invocation != null) {
result =
invokeAndCreateResult(invocation, getProxyForService());
}
} catch (Throwable throwable) {
if (result == null) {
result = new RemoteInvocationResult(throwable);
}
throwable.printStackTrace();
} finally {
writeRemoteInvocationResult(requestMessage, session, result);
// JmsUtils.commitIfNecessary(session);
}
}
FirstServiceImpl class has a saveText method which is invoked when a message is put in FirstQueue-Request. In that method, I am trying to call SecondService method: validateText(textmessage). This message is put on SecondQueue-Request but never read.
You didn't commit session after message send.
It seems to me that you are trying to implement request-reply-by-correlationid logic while at same time working with transacted resources and manual session handling; all within same method (doExecuteRequest() or writeRemoteInvocationResult()). That's a lot of stuff for 20 lines of code. This kind of code is usually used with temporary queues..
Do you really need to write code on session level? Is there a reason why you couldn't just use jmsTemplate to send message, and messageListenerContainer to receive reply?

TransactionTemplate and TransactionManager connection objects

The following code in my DAO works perfectly fine.
public void insert(final Person person) {
transactionTemplate.execute(new TransactionCallback<Void>() {
public Void doInTransaction(TransactionStatus txStatus) {
try {
getJdbcTemplate().execute("insert into person(username, password) values ('" + person.getUsername() + "','" + person.getPassword() + "')");
} catch (RuntimeException e) {
txStatus.setRollbackOnly();
throw e;
}
return null;
}
});
}
Following is my spring config.
<bean id="derbyds" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="username" value="app" />
<property name="password" value="app" />
<property name="url" value="jdbc:derby:mytempdb" />
</bean>
<bean id="persondaojdbc" class="com.napp.dao.impl.PersonDaoJdbcImpl">
<property name="dataSource" ref="derbyds" />
<property name="transactionTemplate">
<bean class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="derbyds"/>
</bean>
What i wanted to know is how does the
<bean id="persondaojdbc" class="com.napp.dao.impl.PersonDaoJdbcImpl">
<property name="dataSource" ref="derbyds" />
<property name="transactionTemplate">
<bean class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="derbyds"/>
</bean>
Now, its imperative that both the TransactionManager and the code (in my case jdbc template) operate on the same connection. I am assuming both of them are getting the Connection objects from the DataSource. DataSource pools connections and its a chance when you call getConnection multiple times, you will get different Connection obejcts. How does spring make sure that the TransactionManager and JdbcTemplate end up getting the same connection objects. My understanding is that, if that doesn't happen, rollbacks, or commits wont work, correct? Could someone throw more light on this.
If you look at the code for JdbcTemplate (one of the execute(...) methods) you will see
Connection con = DataSourceUtils.getConnection(getDataSource());
Which tries to retrieve a Connection from a ConnectionHolder registered with a TransactionSynchronizationManager.
If there is no such object, it just gets a connection from the DataSource and registers it (if it is in a transactional environment, ie. you have a transaction manager). Otherwise, it immediately returns the registered object.
This is the code (stripped of logs and stuff)
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
conHolder.setConnection(dataSource.getConnection());
}
return conHolder.getConnection();
}
// Else we either got no holder or an empty thread-bound holder here.
Connection con = dataSource.getConnection();
// flag set by the TransactionManager
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// Use same Connection for further JDBC actions within the transaction.
// Thread-bound object will get removed by synchronization at transaction completion.
ConnectionHolder holderToUse = conHolder;
if (holderToUse == null) {
holderToUse = new ConnectionHolder(con);
}
else {
holderToUse.setConnection(con);
}
holderToUse.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(holderToUse, dataSource));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != conHolder) {
TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
}
}
return con;
You'll notice that the JdbcTemplate tries to
finally {
DataSourceUtils.releaseConnection(con, getDataSource());
}
release the Connection, but this only happens if you're in a non-transactional environment, ie.
if it is not managed externally (that is, not bound to the thread).
Therefore, in a transactional world, the JdbcTemplate will be reusing the same Connection object.

Spring-JMS(Websphere MQ)

I have the below configurations in Spring , it is working fine but performance is too low (it takes 1 min for 20 messages). Can you please suggest me changes to increase the performance.
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="transportType"><value>1</value></property>
<property name="queueManager"><value></value></property>
<property name="hostName"><value></value></property>
<property name="port"><value></value></property>
<property name="channel"><value></value></property>
<property name="clientId"><value></value></property>
</bean>
<bean id="SenderJMSTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory"><ref bean="jmsConnectionFactory" /> </property>
<property name="pubSubDomain"><value>false</value></property>
<property name="defaultDestination"><ref bean="senderQueue" /></property>
</bean>
<bean id="senderQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="TEST" />
<property name="baseQueueManagerName"><value>tree.queue.manager</value></property>
<property name="baseQueueName"><value>ORANGE.QUEUE</value></property>
</bean>
<bean id="jmsSender" class="org.tree.jms.spring.JMSSender">
<property name="jmsTemplate"><ref bean="SenderJMSTemplate"/></property>
</bean>
I am calling from spring as
JMSSender obj = (JMSSender) context.getBean("jmsSender");
And My Sender program is :
#Cacheable("message")
public void sendMesage() {
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session)throws JMSException {
message = (Message) session.createTextMessage(stringBuffer.toString());
return message;
}
});
}
}
A common problem when using JMSTemplate to send messages out of JavaEE containers is the it's extremly slow since it acquires a new connection for each message (and then closes it). You would probably need a pooled/cached connection to gain speed here.
Read this article, it's written for ActiveMQ, but applies in a similar way to WebSphere MQ: http://activemq.apache.org/jmstemplate-gotchas.html
You can setup a cached connection factory in spring using something like this:
<bean id="cachedConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory"
p:targetConnectionFactory-ref="jmsConnectionFactory"
p:sessionCacheSize="10" />
Then use it instead of the original one for JMS connections.

Resources