Spring?Boot如何排除自動(dòng)加載數(shù)據(jù)源
前言
有些老項(xiàng)目使用Spring MVC里面有寫好的數(shù)據(jù)庫(kù)連接池,比如redis/mongodb/mybatis(mysql其他Oracle同理)。在這些項(xiàng)目遷入spring boot框架時(shí),會(huì)報(bào)錯(cuò)。
原因是我們業(yè)務(wù)寫好了連接池,但spring boot在jar包存在的時(shí)候會(huì)主動(dòng)加載spring boot的autoconfiguration創(chuàng)建連接池,但我們并未配置Spring Boot參數(shù),也不需要配置。
1. mongodb
mongodb自動(dòng)配置錯(cuò)誤如下:
org.mongodb.driver.cluster : Exception in monitor thread while connecting to server localhost:27017
com.mongodb.MongoSocketOpenException: Exception opening socket
Caused by: java.net.ConnectException: Connection refused (Connection refused)
但是我沒(méi)有引入spring-boot-starter-data-mongodb的jar包,后來(lái)發(fā)現(xiàn)我引入了spring-data-mongodb的jar
檢查spring-boot-starter-data-mongodb的jar,包括3部分,如下:

我的jar包都有,相當(dāng)于這些jar拼裝成了 spring-boot-starter-data-mongodb
在Spring Boot中自動(dòng)引入了自動(dòng)配置功能


需要手動(dòng)排除自動(dòng)配置的數(shù)據(jù)源,在SpringBootApplication中exclude
@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
啟動(dòng)不再報(bào)錯(cuò)連接localhost:27017,業(yè)務(wù)正常。原理見(jiàn)Spring Boot官方文檔

2. mybatis
mybatis同理
Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified and no embedded data
***************************
APPLICATION FAILED TO START
***************************
Description:
Cannot determine embedded database driver class for database type NONE
Action:
If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
需要排除
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
3. 原理講解
原理是EnableAutoConfiguration

進(jìn)一步跟蹤:

AutoConfigurationImportSelector這個(gè)類有自動(dòng)加載與排除的邏輯
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
注意加載代碼
getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
/**
* Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
* of the importing {@link Configuration @Configuration} class.
* @param autoConfigurationMetadata the auto-configuration metadata
* @param annotationMetadata the annotation metadata of the configuration class
* @return the auto-configurations that should be imported
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
里面
getExclusions(annotationMetadata, attributes);
/**
* Return any exclusions that limit the candidate configurations.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return exclusions or an empty set
*/
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
excluded.addAll(asList(attributes, "exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
看到了,exclude或者excludeName,當(dāng)然還有一種方法
private List<String> getExcludeAutoConfigurationsProperty() {
if (getEnvironment() instanceof ConfigurableEnvironment) {
Binder binder = Binder.get(getEnvironment());
return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
.orElse(Collections.emptyList());
}
String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
}
通過(guò)application.properties文件配置spring.autoconfigure.exclude
private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
總結(jié)
出現(xiàn)這種錯(cuò)誤多半發(fā)生在引入了spring-boot-starter-mongodb等這樣的starter插件jar,沒(méi)有配置數(shù)據(jù)源url;或者舊業(yè)務(wù)升級(jí)spring boot(筆者就是這種情況)
解決方法
不需要的jar不要引入即可解決問(wèn)題
使用exclude排除,有三種實(shí)現(xiàn)方式exclude、excludeName、spring.autoconfigure.exclude
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Springboot實(shí)現(xiàn)根據(jù)用戶ID切換動(dòng)態(tài)數(shù)據(jù)源
- Springboot動(dòng)態(tài)切換數(shù)據(jù)源的具體實(shí)現(xiàn)與原理分析
- SpringBoot搭建多數(shù)據(jù)源的實(shí)現(xiàn)方法
- SpringBoot 自定義+動(dòng)態(tài)切換數(shù)據(jù)源教程
- tk-mybatis整合springBoot使用兩個(gè)數(shù)據(jù)源的方法
- springboot多數(shù)據(jù)源使用@Qualifier自動(dòng)注入無(wú)效的解決
- springboot 多數(shù)據(jù)源配置不生效遇到的坑及解決
相關(guān)文章
JAVA 集成 PF4J 插件框架的應(yīng)用場(chǎng)景分析
PF4J是一個(gè)強(qiáng)大的Java插件框架,允許開(kāi)發(fā)者將應(yīng)用程序分解為可擴(kuò)展的模塊,本文介紹了PF4J的基本概念和如何在Java項(xiàng)目中集成,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-03-03
Spring Security UserDetails實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Spring Security UserDetails實(shí)現(xiàn)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
IDEA創(chuàng)建Java項(xiàng)目文件并運(yùn)行教程解析
這篇文章主要介紹了IDEA創(chuàng)建Java項(xiàng)目文件并運(yùn)行教程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Java中Redis存儲(chǔ)String類型會(huì)有亂碼的問(wèn)題及解決方案
在java中使用Redis存儲(chǔ)String類型的數(shù)據(jù)時(shí),會(huì)出現(xiàn)亂碼,我寫了一條存儲(chǔ)key為name,值為虎哥的字符串,然后獲取一下這個(gè)key為name的值,打印得到的值,下面通過(guò)實(shí)例代碼介紹Java中Redis存儲(chǔ)String類型會(huì)有亂碼的問(wèn)題及解決方案,一起看看吧2024-04-04
java實(shí)現(xiàn)簡(jiǎn)單學(xué)生管理系統(tǒng)項(xiàng)目
這篇文章主要介紹了java實(shí)現(xiàn)簡(jiǎn)單學(xué)生管理系統(tǒng)項(xiàng)目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-07-07
Spring Boot實(shí)戰(zhàn)之發(fā)送郵件示例代碼
本篇文章主要介紹了Spring Boot實(shí)戰(zhàn)之發(fā)送郵件示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-03-03
application作用域?qū)崿F(xiàn)用戶登錄擠掉之前登錄用戶代碼
這篇文章主要介紹了application作用域?qū)崿F(xiàn)用戶登錄擠掉之前登錄用戶代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11
如何把VS Code打造成Java開(kāi)發(fā)IDE
這篇文章主要介紹了如何把VS Code打造成Java開(kāi)發(fā)IDE,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10

