For some context I am doing a JMS reader and writer in Spring batch using a jsr compliant implementation. I am using the JMSReader and JMS writer classes provided by Spring batch but I am wrapping them in my own reader and writer. I do not have the typical application context available since I am using the JSR approach. The classes are initialized via the job spec or via the batch.xml as per the jsr spec.
The issue I have run into is I have a stand alone batch application that when I define a JMS reader and/or jms writer that creates a connection factory for active mq and sets that as the target factory for spring's JMSTemplate class, the application when done processing does not shut down properly. The alternative using a connection factory for IBM MQ works fine.
Let me provide some code that I have done.
This is where i create my connection factory. There are a couple commented lines of changes I made trying to get the threads that are left alive to die when the app does.
private ConnectionFactory openAMQ() throws IllegalArgumentException{
ActiveMQConnectionFactory targetConnectionFactory = new ActiveMQConnectionFactory();
if(protocol == null){
throw new IllegalArgumentException("Active MQ protocol can not be empty");
}
AMQProtocols proto = AMQProtocols.valueOf(protocol.toUpperCase());
StringBuilder sb = new StringBuilder();
sb.append(proto.getProtocol()).append("://").append(this.host).append(":").append(this.port);
if(amqParams != null && amqParams.trim().length() > 0){
sb.append("?").append(amqParams);
}
targetConnectionFactory.setBrokerURL(sb.toString());
//targetConnectionFactory.setAlwaysSessionAsync(false);
//targetConnectionFactory.setUseAsyncSend(false);
return targetConnectionFactory;
}
Here is where I create the JMSTemplate object
protected JmsTemplate getJMSTemplate(ConnectionFactory targetConnectionFactory){
CachingConnectionFactory ccf = new CachingConnectionFactory();
ccf.setTargetConnectionFactory(targetConnectionFactory);
JmsTemplate template = new JmsTemplate(ccf);
template.setDefaultDestinationName(jmsDefaultDestinationName);
template.setReceiveTimeout(Long.parseLong(jmsReceiveTimeoutValue));
template.setSessionTransacted(Boolean.parseBoolean(jmsSessionTransacted));
//template.setMessageConverter(messageConverter);
return template;
}
And lastly here is the open method of the JMSReader, the writer is nearly identical
public void open(Serializable checkpoint) throws Exception {
//First we need to get our broker specific connection factory
ConnectionFactory targetConnectionFactory = getTargetConnectionFactory();
this.template = getJMSTemplate(targetConnectionFactory);
reader = new JmsItemReader();
reader.setItemType(Class.forName(jmsItemTypeFullyQualifiedName));
reader.setJmsTemplate(template);
}
The threads that I am seeing alive seem to be related to the connection as well as some inactivity monitoring threads. With these staying alive like they are, it prevents a standalone application from shutting down.
Does anyone have any idea how i can configure the connection factory or jms template to stop this from happening, or possibly manage it once the reader is complete to get it to properly shut down.