欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring Boot如何排除自动加载数据源

程序员文章站 2022-03-02 10:27:06
目录前言1. mongodb2. mybatis3. 原理讲解总结解决方法前言有些老项目使用spring mvc里面有写好的数据库连接池,比如redis/mongodb/mybatis(mysql其他...

前言

有些老项目使用spring mvc里面有写好的数据库连接池,比如redis/mongodb/mybatis(mysql其他oracle同理)。在这些项目迁入spring boot框架时,会报错。

原因是我们业务写好了连接池,但spring boot在jar包存在的时候会主动加载spring boot的autoconfiguration创建连接池,但我们并未配置spring boot参数,也不需要配置。

1. mongodb

mongodb自动配置错误如下:

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)

但是我没有引入spring-boot-starter-data-mongodb的jar包,后来发现我引入了spring-data-mongodb的jar

检查spring-boot-starter-data-mongodb的jar,包括3部分,如下:

Spring Boot如何排除自动加载数据源

我的jar包都有,相当于这些jar拼装成了 spring-boot-starter-data-mongodb

在spring boot中自动引入了自动配置功能

Spring Boot如何排除自动加载数据源

Spring Boot如何排除自动加载数据源

需要手动排除自动配置的数据源,在springbootapplication中exclude

@springbootapplication(exclude = {mongoautoconfiguration.class, mongodataautoconfiguration.class})

启动不再报错连接localhost:27017,业务正常。原理见spring boot官方文档

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

Spring Boot如何排除自动加载数据源

进一步跟踪:

Spring Boot如何排除自动加载数据源

autoconfigurationimportselector这个类有自动加载与排除的逻辑

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,当然还有一种方法

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();
	}

通过application.properties文件配置spring.autoconfigure.exclude

private static final string property_name_autoconfigure_exclude = "spring.autoconfigure.exclude";

总结

出现这种错误多半发生在引入了spring-boot-starter-mongodb等这样的starter插件jar,没有配置数据源url;或者旧业务升级spring boot(笔者就是这种情况)

解决方法

不需要的jar不要引入即可解决问题

使用exclude排除,有三种实现方式exclude、excludename、spring.autoconfigure.exclude

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。