Spring Boot如何排除自动加载数据源
前言
有些老项目使用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部分,如下:
我的jar包都有,相当于这些jar拼装成了 spring-boot-starter-data-mongodb
在spring boot中自动引入了自动配置功能
需要手动排除自动配置的数据源,在springbootapplication中exclude
@springbootapplication(exclude = {mongoautoconfiguration.class, mongodataautoconfiguration.class})
启动不再报错连接localhost:27017,业务正常。原理见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
进一步跟踪:
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
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
上一篇: java基础语法(JavaSE)
推荐阅读
-
谈谈Spring Boot 数据源加载及其多数据源简单实现(小结)
-
Spring boot如何快速的配置多个Redis数据源
-
你知道如何自动保存 Spring Boot 应用进程号吗
-
Spring boot 国际化自动加载资源文件去除默认国际化文件
-
Spring Boot如何排除自动加载数据源
-
Spring boot如何快速的配置多个Redis数据源
-
Spring Boot 如何整合多个数据源?
-
Spring Boot 动态数据源(yml配置,多数据源自动切换)
-
Spring Boot教程十四:基于自定义注解的AOP数据源自动切换
-
spring boot 2.0 Web项目开发时修改Java文件不能自动热加载问题