sbelvadi
sbelvadi

Reputation: 47

Spring configuration (annotation based): NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.jms.ConnectionFactory' available:

spring configuration: Trying to instantiate a JmsMessageListenerContainerFactory Bean that will use a specific connection factory bean instance using annotations.

@Configuration
public class DemoJmsConfig {

    @Value("${jms.context.factory}") 
    private String initialContextFactory;

    @Value("${jms.provider.url}") 
    String jmsProviderUrl;

    //Inbound
    @Value("${jms.inbound.qcf.userName}") 
    private String inboundQcfUserName;

    @Value("${jms.inbound.qcf.password}") 
    private String inboundQcfPassword;

    @Value("${jms.inbound.queue.connectionfactory}") 
    private String inboundQueueConnectionFactory;

    @Value("${jms.inbound.queue.name}")
    private String inboundQueueName;

    @Value("${jms.inbound.initial.cache.size}") 
    private String inboundInitCacheSize;

    //Outbound
    @Value("${jms.outbound.topic.connectionfactory}") 
    private String outboundTopicConnectionFactory;

    @Value("${jms.outbound.topic.name}")
    private String outboundTopicName;

    @Value("${jms.outbound.tcf.userName}") 
    private String outboundTcfUserName;

    @Value("${jms.outbound.tcf.password}") 
    private String outboundTcfPassword;

    @Value("${jms.outbound.initial.cache.size}") 
    private String outboundInitCacheSize;

    @Bean
    public InitialContext initialContext() throws NamingException {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY,
                initialContextFactory);
        props.put(Context.PROVIDER_URL, jmsProviderUrl);

        // Create the initial context from the properties we just created
        return new InitialContext(props);
    }

    @Bean(name="inboundConnectionFactory")
    @Qualifier("inboundConnectionFactory")
    public ConnectionFactory inboundConnectionFactory() throws NamingException {

        //Create a Connection Factory adapter with user credentials
        UserCredentialsConnectionFactoryAdapter uccfa = new UserCredentialsConnectionFactoryAdapter();
        ConnectionFactory cf = (ConnectionFactory) initialContext().lookup(inboundQueueConnectionFactory);
        uccfa.setTargetConnectionFactory(cf);
        uccfa.setUsername(inboundQcfUserName);
        uccfa.setPassword(inboundQcfPassword);

        CachingConnectionFactory ccf = new CachingConnectionFactory();
        if(inboundInitCacheSize != null && Integer.parseInt(inboundInitCacheSize) > 0){
            ccf.setSessionCacheSize(Integer.parseInt(inboundInitCacheSize)); //Default is 1
        }
        ccf.setTargetConnectionFactory(uccfa);
        return ccf;

    }

    @Bean(name="inboundJMSTemplate")
    @Qualifier("inboundJMSTemplate")
    public JmsTemplate inboundJMSTemplate(@Qualifier("inboundConnectionFactory") ConnectionFactory inboundConnectionFactory ) throws NamingException{
        JmsTemplate jmsTemplate = new JmsTemplate();
        jmsTemplate.setConnectionFactory(inboundConnectionFactory);
        jmsTemplate.setDefaultDestinationName(inboundQueueName);
        return jmsTemplate;

    }


    @Bean(name="inboundJmsListenerContainerFactory")
    @Qualifier("inboundJmsListenerContainerFactory")
    public JmsListenerContainerFactory<?> inboundJmsListenerContainerFactory(
            DefaultJmsListenerContainerFactoryConfigurer configurer,
            @Qualifier("inboundConnectionFactory") ConnectionFactory inboundConnectionFactory)
            throws NamingException {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        // This provides all boot's default to this factory, including the
        // message converter
        configurer.configure(factory, inboundConnectionFactory);
        // You could still override some of Boot's default if necessary.
        return factory;
    }


    @Bean(name="outboundConnectionFactory")
    @Qualifier("outboundConnectionFactory")
    public ConnectionFactory outboundConnectionFactory() throws NamingException {

        //Create a Connection Factory adapter with user credentials
        UserCredentialsConnectionFactoryAdapter uccfa = new UserCredentialsConnectionFactoryAdapter();
        ConnectionFactory cf = (ConnectionFactory) initialContext().lookup(outboundTopicConnectionFactory);
        uccfa.setTargetConnectionFactory(cf);
        uccfa.setUsername(outboundTcfUserName);
        uccfa.setPassword(outboundTcfPassword);

        CachingConnectionFactory ccf = new CachingConnectionFactory();
        if(outboundInitCacheSize != null && Integer.parseInt(outboundInitCacheSize) > 0){
            ccf.setSessionCacheSize(Integer.parseInt(outboundInitCacheSize)); //Default is 1
        }
        ccf.setTargetConnectionFactory(uccfa);
        return ccf;

    }

    @Bean(name="outboundErrorJMSTemplate")
    @Qualifier("outboundErrorJMSTemplate")
    public JmsTemplate outboundErrorJMSTemplate(@Qualifier("outboundConnectionFactory") ConnectionFactory outboundConnectionFactory ) throws NamingException{
        JmsTemplate jmsTemplate = new JmsTemplate();
        jmsTemplate.setConnectionFactory(outboundConnectionFactory);
        jmsTemplate.setDefaultDestinationName(outboundTopicName);
        return jmsTemplate;

    }



}

Expected result: The JmsListenerContainerFactory is instantiated.

Actual:

*************************** APPLICATION FAILED TO START
***************************

Description:

Parameter 1 of method jmsListenerContainerFactory in org.springframework.boot.autoconfigure.jms.JmsAnnotationDrivenConfiguration required a single bean, but 2 were found:
    - inboundConnectionFactory: defined by method 'inboundConnectionFactory' in class path resource [com/example/demo/config/DemoJmsConfig.class]
    - outboundConnectionFactory: defined by method 'outboundConnectionFactory' in class path resource [com/example/demo/config/DemoJmsConfig.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

[WARNING]  java.lang.reflect.InvocationTargetException  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)    at java.lang.reflect.Method.invoke(Method.java:483)     at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:527)    at java.lang.Thread.run(Thread.java:745) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jmsListenerContainerFactory' defined in class path resource [org/springframework/boot/autoconfigure/jms/JmsAnnotationDrivenConfiguration.class]: Unsatisfied dependency expressed through method 'jmsListenerContainerFactory' parameter 1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.jms.ConnectionFactory' available: expected single matching bean but found 2: inboundConnectionFactory,outboundConnectionFactory   at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)  at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:467)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173)     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067)    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)   at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)  at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)   at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)  at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)   at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)  at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)  at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)  at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)   at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)    at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)   at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118)  at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107)  at com.example.demo.DemoApplication.main(DemoApplication.java:10)   ... 6 more Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.jms.ConnectionFactory' available: expected single matching bean but found 2: inboundConnectionFactory,outboundConnectionFactory  at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:173)    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116)   at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)     at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835)     at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)  ... 25 more

I have tried specifying qualifiers, bean names.. still getting errors. Can anyone suggest what I should do to resolve this. I need both the inbound and outbound connections since the application will consume and publish

Upvotes: 0

Views: 7064

Answers (2)

Carlos Lacerda
Carlos Lacerda

Reputation: 699

Check this question Spring Boot multiple JMS connections that can help you. If in your case are using a mix of Spring XML and annotations to make a connection factory, maybe you can have problems with SpringBoot, in this case thy disable autostart of spring-boot-jms with this in your application:

 @SpringBootApplication(exclude = {JmsAutoConfiguration.class})

this was my case.

Upvotes: 0

sbelvadi
sbelvadi

Reputation: 47

resolved by adding @Primary to inbound Connection factory

Upvotes: 3

Related Questions