Spring Cloud環境下多數據源的配置要點(實戰)

 

最近在搭建Spring Cloud新項目,遇到了這個問題,記錄一下,以饗讀者。

 

關於怎麼配置多數據源,這裏不再贅述,簡單來說,就是配置多個bean,每個bean對應一個數據源。

有不懂的讀者,可以參考我之前的一篇博客,或者在網上搜素,都可以。

如何配置多數據源

這篇博客比較老了,用的是xml配置文件。但是萬變不離其宗,本質上是一樣的,就是注入多個bean到Spring的IOC容器中。

 

在Spring Cloud環境下,我們配置了2個數據源以後,啓動項目會報錯。

 

報錯日誌如下:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Injection of autowired dependencies failed;

nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.dataSource;

nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [cn/sephora/platform/oms/backend/config/DataSourceConfig.class]: Initialization of bean failed;

nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocation of init method failed;

nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: monitorDataSource,dataSource

 

更詳細的堆棧日誌如下:

2020-05-25 13:14:09,669 [main] ERROR org.springframework.boot.SpringApplication - [ -  - ] - Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.dataSource; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [cn/sephora/platform/oms/backend/config/DataSourceConfig.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocation of init method failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: monitorDataSource,dataSource
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
	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.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:368)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
	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.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1054)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:829)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
	at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:760)
	at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:360)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:306)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1185)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1174)
	at cn.sephora.platform.oms.backend.Application.main(Application.java:26)

 

爲什麼呢?很簡單,你配置了2個數據源,都是javax.sql.DataSource的實現。

DataSourceAutoConfiguration這個類也向IOC容器注入了一個DataSource,這個DataSource是Spring集成的原生的DataSource。


 

那麼問題來了,當DataSourceAutoConfiguration向Spring的IOC容器中注入DataSource實例時,發現這個DataSource有2個實現,

Spring的IOC容器不知道該使用哪個?於是就拋出了上面的異常。

 

解決方案如下:在Spring啓動時,不要加載這個DataSourceAutoConfiguration就行了。

如下:在SpringBootApplication註解上,排除掉DataSourceAutoConfiguration.class

 

@SpringBootApplication(exclude={
        DataSourceAutoConfiguration.class
})
public class Application {

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);
    }
}

 

這裏告訴我們一個要點:Spirng Cloud環境下,如果需要配置多數據源的話,一定不要注入DataSourceAutoConfiguration.class

 

更多關於搭建Spring Cloud項目的分享,稍後會奉上。

 


 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章