1

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.

Mark Kouba
  • 236
  • 2
  • 12

1 Answers1

0

I think I answered my own question. On the CachingConnectionFactory I added a call to the destroy method in the close method of both the jms read and writer. I do have some concern that calling that does not allow proper clean up, but it is allowing the app to shut down rather than hang.

Mark Kouba
  • 236
  • 2
  • 12