【问题标题】:Spring Boot Embedded Tomcat - No qualifying bean of type 'javax.sql.DataSource' available: expected single matching bean but found 3Spring Boot Embedded Tomcat - 没有可用的“javax.sql.DataSource”类型的合格 bean:预期单个匹配 bean,但找到了 3
【发布时间】:2018-01-11 03:12:38
【问题描述】:

我正在开发我的 Spring Boot 应用程序并使用嵌入式 tomcat 8.x 运行。我正在尝试使用 JNDI 配置三个不同的 oracle 数据源并遵循此link。以下是我的不同文件:

application-dev.properties

spring.oracle.datasource.oracleDS1.jndi-name=jdbc/oracleDS1
spring.oracle.datasource.oracleDS2.jndi-name=jdbc/oracleDS2
spring.oracle.datasource.oracleDS3.jndi-name=jdbc/oracleDS3

OracleDataSourceConfiguration

package com.adp.orbis.requesttracker.orbisrequesttracker;

import javax.sql.DataSource;

    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.context.annotation.Profile;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;

    @Configuration
    public class OracleDataSourceConfiguration {

        @Value("${spring.oracle.datasource.oracleDS1.jndi-name}")
        private String oracleDS1;

        @Value("${spring.oracle.datasource.oracleDS2.jndi-name}")
        private String oracleDS2;

        @Value("${spring.oracle.datasource.oracleDS3.jndi-name}")
        private String oracleDS3;

        @Bean(name="dataSource1", destroyMethod = "")
        @Profile("dev")
        @Primary
        public DataSource evolutionDataSource() {
            JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
            return dataSourceLookup.getDataSource(oracleDS1);
        }

        @Bean(name="dataSource2", destroyMethod = "")
        @Profile("dev")
        @Primary
        public DataSource orbisQueryOnlyDataSource() {
            JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
            return dataSourceLookup.getDataSource(oracleDS2);
        }

        @Bean(name="dataSource3", destroyMethod = "")
        @Profile("dev")

        public DataSource orbisExportDataSource() {
            JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
            return dataSourceLookup.getDataSource(oracleDS3);
        }
    }

TomcatEmbeddedServletContainerFactory

@Bean
    public TomcatEmbeddedServletContainerFactory tomcatFactory() {
        return new TomcatEmbeddedServletContainerFactory() {

            @Override
            protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
                tomcat.enableNaming();
                return super.getTomcatEmbeddedServletContainer(tomcat);
            }

            @Override
            protected void postProcessContext(Context context) {
                ContextResource oracleDS1JNDIResource = new ContextResource();
                oracleDS1JNDIResource.setName("jdbc/oracleDS1");
                oracleDS1JNDIResource.setType(DataSource.class.getName());
                oracleDS1JNDIResource.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver");
                oracleDS1JNDIResource.setProperty("url", "jdbc:oracle:thin:@localhost:1521/mydbservice1");
                oracleDS1JNDIResource.setProperty("username", "db-user-name");
                oracleDS1JNDIResource.setProperty("password", "db-user-pass");
                oracleDS1JNDIResource.setProperty("factory", "org.apache.tomcat.jdbc.pool.DataSourceFactory");
                context.getNamingResources().addResource(oracleDS1JNDIResource);

                ContextResource oracleDS2JNDIResource = new ContextResource();
                oracleDS2JNDIResource.setName("jdbc/oracleDS2");
                oracleDS2JNDIResource.setType(DataSource.class.getName());
                oracleDS2JNDIResource.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver");
                oracleDS2JNDIResource.setProperty("url", "jdbc:oracle:thin:@localhost:1521/mydbservice2");
                oracleDS2JNDIResource.setProperty("username", "db-user-name");
                oracleDS2JNDIResource.setProperty("password", "db-user-pass");
                oracleDS2JNDIResource.setProperty("factory", "org.apache.tomcat.jdbc.pool.DataSourceFactory");
                context.getNamingResources().addResource(oracleDS2JNDIResource);

                ContextResource oracleDS3JNDIResource = new ContextResource();
                oracleDS3JNDIResource.setName("jdbc/oracleDS3");
                oracleDS3JNDIResource.setType(DataSource.class.getName());
                oracleDS3JNDIResource.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver");
                oracleDS3JNDIResource.setProperty("url", "jdbc:oracle:thin:@localhost:1521/mydbservice3");
                oracleDS3JNDIResource.setProperty("username", "db-user-name");
                oracleDS3JNDIResource.setProperty("password", "db-user-pass");
                oracleDS3JNDIResource.setProperty("factory", "org.apache.tomcat.jdbc.pool.DataSourceFactory");
                context.getNamingResources().addResource(oracleDS3JNDIResource);                

            }
        };
    }

但是当我运行这个 Spring Boot 应用程序时,它会抛出异常。你能帮我这里缺少什么吗?我尝试在所有 DataSource bean 中添加 @Primary。但没有运气。

org.springframework.beans.factory.NoUniqueBeanDefinitionException:没有“javax.sql.DataSource”类型的合格 bean 可用:预期单个匹配 bean,但找到了 3:dataSource1、dataSource2、dataSource3

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected single matching bean but found 3: dataSource1,dataSource2,dataSource3
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1041) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:345) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1092) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer.init(DataSourceInitializer.java:77) ~[spring-boot-autoconfigure-1.5.9.RELEASE.jar:1.5.9.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_112]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_112]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_112]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_112]
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:366) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:311) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:134) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    ... 38 common frames omitted

【问题讨论】:

标签: spring-boot datasource jndi embedded-tomcat-8


【解决方案1】:

应该至少有 1 个名称为 dataSource 的 bean。所以要么用 exp dataSource1dataSource 的名称替换任何现有的 bean,或者创建一个新的。

想说,改变

@Bean(name="dataSource1", destroyMethod = "")
@Profile("dev")
@Primary
public DataSource evolutionDataSource() {
     JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
            return dataSourceLookup.getDataSource(oracleDS1);
}

@Bean(name="dataSource", destroyMethod = "")
@Profile("dev")
@Primary
public DataSource evolutionDataSource() {
    JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
            return dataSourceLookup.getDataSource(oracleDS1);
}


只需从任何现有的dataSource* bean 中删除@Primary。同一@Profile下最多可以有1个bean @Primary

【讨论】:

  • 感谢您的评论。我试过你的两种选择。但没有运气。我已经有至少一个 bean 名称作为 dataSource。
【解决方案2】:

我能够解决这个问题。问题是,我已经在我的 Spring Boot 应用程序中定义了所有数据源,并且它还在导入相关的 Spring 上下文文件。这意味着,我在导入的 spring 上下文文件中也配置了相同的数据源。我从 OracleDataSourceConfiguration 中删除了所有数据源 bean(如我在上面的问题中所提到的),并使用 TomcatEmbeddedServletContainerFactory 来初始化具有相同名称的 JNDI 数据源(称为 this),这些名称在我导入的 spring 上下文文件中提到。它对我有用。

 <jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDataSource" />

【讨论】:

    猜你喜欢
    • 2021-06-14
    • 2019-04-08
    • 1970-01-01
    • 2018-02-08
    • 2018-10-05
    • 2017-12-11
    • 2020-01-31
    • 2019-08-06
    • 2015-02-01
    相关资源
    最近更新 更多