0
votes

I have defined a bean in dispatcher-servlet.xml like this:

<!-- Datasource configuration -->
<beans:bean id="dataSource" name="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">      
   <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
   <beans:property name="url" value="" />
   <beans:property name="username" value="" />
   <beans:property name="password" value="" /> 
</beans:bean>

In another config.class (this time using Java Annotation for configuration) I would want to override this bean. This is the definition of the new bean:

@ImportResource(dispatcher-servlet.xml)

    @Bean
    @Primary
    public EmbeddedDatabase dataSource() {
        EmbeddedDatabaseBuilder databaseBuilder = new EmbeddedDatabaseBuilder();
        databaseBuilder.setName("testDB");
        databaseBuilder.setType(EmbeddedDatabaseType.H2);

        return databaseBuilder.build();
    }

In a test I write:

@ContextConfiguration(classes = config.class)
@WebAppConfiguration
// Test

The unexpected result is that the bean with id dataSource that Spring chooses is the one defined in the xml file. This is the output logged:

[info] Overriding bean definition for bean 'dataSource' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=true; factoryBeanName=Config; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in ... with [Generic bean: class [org.springframework.jdbc.datasource.DriverManagerDataSource]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL [dispatcher-servlet.xml]]


It seems that @Primary Annotation is ignored.
Why? What is the solution?

2

2 Answers

2
votes

I'm not sure it is a good idea to mix different configuration types. If I were to read that kind of configuration, I would probably struggle, and believe me, I actually done quite a bit.

But, as the answer for your question, XML takes precedence over annotations. So, try to declare your bean in an XML, or use only annotations in your application.

You might try with the @Qualifier annotation. Maybe like this:

@Bean
@Qualifier("my_qualifier")
public EmbeddedDatabase dataSource() {
    EmbeddedDatabaseBuilder databaseBuilder = new EmbeddedDatabaseBuilder();
    databaseBuilder.setName("testDB");
    databaseBuilder.setType(EmbeddedDatabaseType.H2);

    return databaseBuilder.build();
}

And inject it using:

@Autowired
@Qualifier("my_qualifier")
EmbeddedDatabase database;

But I'm still not sure shall it work.

P.S. If you have not set up automatic annotation scanning, you should add this to you XML. From the comments you mentioned it is obsolete, but it is not.

<context:component-scan base-package="your.base.package" />

Just put a package containing all of your annotated classes instead of your.base.package, and they should be picked up by Spring, because I'm still not convinced Spring is picking them up.

1
votes

According to @Primary Javadoc XML configuration has precedence before Java based configuration:

If a @Primary-annotated class is declared via XML, @Primary annotation metadata is ignored, and <bean primary="true|false"/> is respected instead.

As a result bean from XML configuration will not be overridden.