Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring-Boot ignores @Qualifier annotation

I am migrating an active Spring web app to spring boot(1.4.2).

The beans are defined in an XML as it is being loaded with @ImportResource.

4 of the beans that I am starting are an instance of the same object BasicDataSource.

To tell spring which one to load I have set an ID for each one and using @Qualifier to bind the correct bean to the variable.

But it seems to be that Spring ignores my @Qualifier and throwing "No qualifying bean of type 'javax.sql.DataSource' available: expected single matching bean but found 4: DataSource1, DataSource2, DataSource3, DataSource4"

P.S - Note that the class that has the @Qualifier is an abstract class, and the class that is failing to instantiate is an extending class, however @Qualifier has @Inherited.

XML

<beans
    xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:task="http://www.springframework.org/schema/task"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
   http://www.springframework.org/schema/aop 
   http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.2.xsd
   http://www.springframework.org/schema/jee 
   http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
   http://www.springframework.org/schema/task 
   http://www.springframework.org/schema/task/spring-task-3.2.xsd
   http://www.springframework.org/schema/cache
   http://www.springframework.org/schema/cache/spring-cache-3.2.xsd
   http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
   http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.1.xsd">

<context:load-time-weaver aspectj-weaving="on"/>
<cache:annotation-driven mode="aspectj"/>
<context:property-override location="file:/app/config/dataSourceOverride.cfg"/>
<context:annotation-config />

<bean id="DataSource1" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="userId" value="4" />
</bean>

<bean id="DataSource2" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="userId" value="3" />
</bean>

<bean id="DataSource3" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="userId" value="2" />
</bean>

<bean id="DataSource4" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="userId" value="1" />
</bean>

Spring boot app main

package com.app;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportResource;


@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan("com.app")
@ImportResource("com/app/startup/spring.xml")
public class SpringBootServer {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootServer.class, args);

    }
}

Abstract Class

public abstract class GenericDao {

    public GenericDao() {

    }

    private Logger logger = LoggerFactory.getLogger(GenericDao.class);

    @Autowired
    @Qualifier("DataSource1")
    protected BasicDataSource dataSource1Impl;

    @Autowired
    @Qualifier("DataSource2")
    protected BasicDataSource dataSource2Impl;

    @Autowired
    @Qualifier("DataSource3")
    protected BasicDataSource dataSource3Impl;

    @Autowired
    @Qualifier("DataSource4")
    protected BasicDataSource dataSource4Impl;
}

Solid Calss

@Component("widgetsDao")
public class WidgetsDao extends GenericDao {

##Some methods##

}

Exception

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

Description:

Field dataSource1Impl in com.app.dal.GenericDao required a single bean, but 4 were found:
    - DataSource1: defined in class path resource [com/app/startup/app-spring.xml]
    - DataSource2: defined in class path resource [com/app/startup/app-spring.xml]
    - DataSource3: defined in class path resource [com/app/startup/app-spring.xml]
    - DataSource4: defined in class path resource [com/app/startup/app-spring.xml]


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

What could possibly make spring to ignore my @Qualifier annotation??

Thanks Ahead.

like image 410
Ronco Avatar asked Dec 19 '16 16:12

Ronco


1 Answers

I was seeing the same error when using multiple data sources, and after making one of the data source beans "primary" the issue seemed to be resolved and I was then able to autowire the correct bean with the @Qualifier annotation.

The Spring Boot documentation here agrees with that, saying that when using multiple data sources, one of the data source beans must be primary.

I configured my beans in Java using @Bean annotation, and so I used @Primary annotation to make one primary. But if you're configuring in XML it looks like the element in XML does have an optional "primary" attribute that could be used if configuring the beans in XML.

like image 68
Jake Kugel Avatar answered Oct 13 '22 16:10

Jake Kugel