0
votes

Below is the code in which I am trying to create a dynamic Listenercontainer instance after the application has been deployed. Without the message selector(the commented code), I am able to see my messages being consumed. Once I am adding the setMessageSelector the message is not getting consumed. I configured the producers to produce messages with two different message selectors, say color='RED' and another one color='BLUE'. I have wired the 'RED' one using the Spring XML configuration. And this configuration works without any issues. I am able to see the message being consumed by consumers. But when I am trying to create a dynamic bean with color='BLUE' it does not work. The same will work without any issues if I add it in spring XML

'''

DefaultMessageListenerContainer defaultMessageListenerContainer=new DefaultMessageListenerContainer();
       defaultMessageListenerContainer.setAutoStartup(Boolean.FALSE);
       defaultMessageListenerContainer.setMessageListener(this.getMessageListener());
       //defaultMessageListenerContainer.setMessageSelector(this.getMessageSelector());
       defaultMessageListenerContainer.setBeanName(this.getBeanName());
       defaultMessageListenerContainer.setConnectionFactory(this.getConnectionFactory());
       defaultMessageListenerContainer.setDestination((Destination) this.getApplicationContext().getBean("customDestination"));
       defaultMessageListenerContainer.setSessionTransacted(Boolean.TRUE);
       defaultMessageListenerContainer.setConcurrentConsumers(1);
       defaultMessageListenerContainer.setMaxConcurrentConsumers(5);
       defaultMessageListenerContainer.initialize();
       defaultMessageListenerContainer.afterPropertiesSet();
       defaultMessageListenerContainer.start();
       System.out.println(defaultMessageListenerContainer.isRunning());
       System.out.println(defaultMessageListenerContainer.isAcceptMessagesWhileStopping());
       System.out.println(defaultMessageListenerContainer.isRegisteredWithDestination());
       ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory();
       beanFactory.registerSingleton("jmsRequestListenerContainer", defaultMessageListenerContainer);

<bean id="jmsRequestListenerContainerdefault" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
    <property name="concurrentConsumers" value="1" />
    <property name="maxConcurrentConsumers" value="5" />
    <property name="cacheLevel"      value="0"/>
    <property name="connectionFactory"   ref="queueConnectionFactory" />
    <property name="destination"          ref="customeDestination"/>
    <property name="sessionTransacted"  value="true"/>
    <property name="messageListener" ref="jmsRequestListener" />
    <property name="messageSelector" value="color='RED'"/>
</bean>


<jee:jndi-lookup id="queueConnectionFactory" jndi-name="java:/JmsXA"/>

'''

Am I missing something in the code while creating it dynamically after the application has launched?

1
Are you sure? That XML is not valid - you have 2 messageSelector properties (not allowed) and cacheLevelName cannot accept numbers, should be cacheLevel. - Gary Russell
I have corrected the XML. I had only one message selector in my sample app. - mags
You still have <property name="cacheLevelName" value="0"/> which is not valid. See my answer; I have no problems adding selectors at runtime. - Gary Russell
You are right I have changed it to cacheLevel - mags

1 Answers

1
votes

This works fine for me...

@SpringBootApplication
public class So66359276Application {

    public static void main(String[] args) throws InterruptedException {
        ConfigurableApplicationContext ctx = SpringApplication.run(So66359276Application.class, args);
        Thread.sleep(5_000);
        ctx.close();
    }

    @Bean
    public ApplicationRunner runner(JmsTemplate template, ConnectionFactory cf, GenericApplicationContext ctx) {
        template.setDefaultDestinationName("foo");
        return args -> {
            createContainer("RED", new JmsRequestListener1(), cf, ctx);
            createContainer("BLUE", new JmsRequestListener2(), cf, ctx);
            IntStream.range(0, 10).forEach(i -> {
                template.convertAndSend("foo" + i, msg -> {
                    msg.setStringProperty("color", "RED");
                    return msg;
                });
            });
            IntStream.range(0, 10).forEach(i -> {
                template.convertAndSend("bar" + i, msg -> {
                    msg.setStringProperty("color", "BLUE");
                    return msg;
                });
            });
        };
    }

    private void createContainer(String color, MessageListener listener, ConnectionFactory cf,
            GenericApplicationContext ctx) {

        DefaultMessageListenerContainer container = new DefaultMessageListenerContainer();
        container.setConnectionFactory(cf);
        container.setSessionTransacted(true);
        container.setDestinationName("foo");
        container.setMessageSelector("color='" + color + "'");
        container.setMessageListener(listener);
        ctx.registerBean("container" + color, DefaultMessageListenerContainer.class, () -> container);
        ctx.getBean("container" + color, DefaultMessageListenerContainer.class).start();
    }

}

class JmsRequestListener1 implements MessageListener {

    @Override
    public void onMessage(Message message) {
        try {
            System.out.println("1:" + ((TextMessage) message).getText() + " - "
                    + message.getStringProperty("color"));
        }
        catch (JMSException e) {
            e.printStackTrace();
        }
    }

}

class JmsRequestListener2 implements MessageListener {

    @Override
    public void onMessage(Message message) {
        try {
            System.out.println("2:" + ((TextMessage) message).getText() + " - "
                    + message.getStringProperty("color"));
        }
        catch (JMSException e) {
            e.printStackTrace();
        }
    }

}
1:foo0 - RED
1:foo1 - RED
1:foo2 - RED
1:foo3 - RED
1:foo4 - RED
1:foo5 - RED
1:foo6 - RED
1:foo7 - RED
1:foo8 - RED
1:foo9 - RED
2:bar0 - BLUE
2:bar1 - BLUE
2:bar2 - BLUE
2:bar3 - BLUE
2:bar4 - BLUE
2:bar5 - BLUE
2:bar6 - BLUE
2:bar7 - BLUE
2:bar8 - BLUE
2:bar9 - BLUE

registerBean is a newer way of adding bean definitions at runtime, but using registerSingleTon should work too.