1.问题描述:springboot3 + JDk17项目整合多数据源,遇到了
DruidDataSourceAutoConfigure和DynamicDataSourceAutoConfiguration冲突
这两个类刚好存在相同名称类型不通过的bean。
我引入的依赖
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
</dependency>
版本
<mysql.version>8.0.31</mysql.version>
<druid.version>1.2.22</druid.version>
<mybatis-plus.version>3.5.7</mybatis-plus.version>
<dynamic.version>4.3.0</dynamic.version>
2.选择排除对象
DruidDataSourceAutoConfigure和DynamicDataSourceAutoConfiguration是通过springbooot的imports文件加载的;这里选择排除DruidDataSourceAutoConfigure
原因:
DynamicDataSourceAutoConfiguration通过import注解导入的DruidDynamicDataSourceConfiguration内容如下
正好将DruidDataSourceAutoConfigure包含在内了
3.如何排除
系统框架是有一个common模块,改模块下存在许多子模块,而业务模块通过引入不同的common模块,添加不同的功能。系统模块的路径和common模块的路径是不同的,因此是采用imports加载common的配置类。
1.第一次采用@EnableAutoConfiguration注解排除
启动如下:
MybatisAutoConfiguration本身就存在org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中,而kui-common-datasource模块又被添加到system业务模块中,导致了循环导入问题。
排除一种,因为路径不同,然后我希望业务模块引入kui-common-datasource模块就可以在配置文件中添加数据库,不同修改启动类代码,也不需要添加注解什么的,所以我不能排除imports文件方式,但是怎么排除呢,难道每一个业务模块添加了该模块都在@SpringBootApplication注解上去排除吗?最好模块内部自己就解决这个问题。
2.分析主要还是EnableAutoConfiguration这个注解
主要是AutoConfigurationImportSelector这个类
进入getExclusions这个方法看看
可以发现有三处来源,第一二处来源于注解,但是还有第三处,这里查找了环境配置中的属性spring.autoconfigure.exclude
3.向环境中添加值
现在知道还有第三处来源,现在问题是如何向environment添加了。
这个和BeanPostProcessor,BeanDefinitionRegistryPostProcessor一样都是后置处理器,可以在bean或者BeanDefinition注册的时候做前后处理,不同的是这个是处理environment环境的。
创建自定义的后置处理器,将自定义的后置处理器放到META-INF/spring.factories文件中
自定义MybatisEnvironmentPostProcessor
package com.kui.mall.common.datasource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.env.*;
/**
* DruidDataSourceAutoConfigure和DynamicDataSourceAutoConfiguration冲突
* 解决方法:通过environment添加排除配置类,排除DruidDataSourceAutoConfigure
*/
public class MybatisEnvironmentPostProcessor implements EnvironmentPostProcessor {
private static final String EXCLUDE_KEY = "spring.autoconfigure.exclude";
private static final String BEAN_NAME = "com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure";
private static final String PROPERTY_SOURCE_NAME = "mybatis-exclude-bean";
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
MutablePropertySources propertySources = environment.getPropertySources();
PropertySource<?> existingPropertySource = propertySources.get(EXCLUDE_KEY);
if (existingPropertySource != null) {
String existingValue = (String) existingPropertySource.getProperty(EXCLUDE_KEY);
String newValue = existingValue != null ? existingValue + "," + BEAN_NAME : BEAN_NAME;
propertySources.replace(PROPERTY_SOURCE_NAME, new PropertySource<>(PROPERTY_SOURCE_NAME, newValue) {
@Override
public Object getProperty(String name) {
if (EXCLUDE_KEY.equals(name)) {
return newValue;
}
return null;
}
});
} else {
// 如果不存在 mybatis-exclude-bean 属性源,创建新的属性源
propertySources.addFirst(new PropertySource<>(PROPERTY_SOURCE_NAME, BEAN_NAME) {
@Override
public Object getProperty(String name) {
if (EXCLUDE_KEY.equals(name)) {
return BEAN_NAME;
}
return null;
}
});
}
}
}
org.springframework.boot.env.EnvironmentPostProcessor=\
com.kui.mall.common.datasource.MybatisEnvironmentPostProcessor
启动,这次就成功了。