Search code examples
javaspringspring-bootspring-context

Spring Boot application context interferes with separate ClassPathXmlApplicationContext


Because I have to work with a legacy application, I want to use beans from a separate Spring context.

I create this separate Spring context with an XML beans definition like this:

<?xml version="1.0" encoding="UTF-8"?>
<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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

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

    <bean id="connectionUrlFactory" class="my.ConnectionUrlFactory">
        <property name="dbServer" value="server.url.com"/>
        <property name="dbDatabasename" value="database"/>
        <property name="dbClientName" value="client"/>
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.sybase.jdbc4.jdbc.SybDriver"/>
        <property name="url" ref="connectionUrlFactory"/>
        <property name="username" value="user"/>
        <property name="password" value="password"/>
    </bean>

</beans>

In my own, "outer" Spring Boot application, I have a context @Configuration like this:

@Configuration
class Configuration {

    private final ApplicationContext applicationContext;

    Configuration() {
        applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    }

    @Bean
    DaoSybaseImpl sybaseDao() {
        return applicationContext.getBean(DaoSybaseImpl.class);
    }

    @Bean
    DataSource sybaseDataSource() {
        return applicationContext.getBean(DataSource.class);
    }

}

However, when I run the application, I get this error:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sybaseDao': Unsatisfied dependency expressed through method 'setDataSource' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected single matching bean but found 2: postgresDataSource,sybaseDataSource
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:768)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:720)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1413)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
    ... 125 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected single matching bean but found 2: postgresDataSource,sybaseDataSource
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:220)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1358)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:760)
    ... 140 more

When I remove sybaseDataSource from my @Configuration, the error disappears (my application then doesn't start because it's missing sybaseDataSource).

It seems that the legacy ClassPathXmlApplicationContext does know of my "outer" Spring Boot context. How can this be?


Solution

  • I have now removed the "outer" Spring application. With plain Java code I can load the other context without interference.