springboot3整合多数据源,冲突问题

153 阅读2分钟

1.问题描述:springboot3 + JDk17项目整合多数据源,遇到了 DruidDataSourceAutoConfigure和DynamicDataSourceAutoConfiguration冲突 image.png image.png 这两个类刚好存在相同名称类型不通过的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
原因: image.png DynamicDataSourceAutoConfiguration通过import注解导入的DruidDynamicDataSourceConfiguration内容如下 image.png 正好将DruidDataSourceAutoConfigure包含在内了 image.png

3.如何排除

系统框架是有一个common模块,改模块下存在许多子模块,而业务模块通过引入不同的common模块,添加不同的功能。系统模块的路径和common模块的路径是不同的,因此是采用imports加载common的配置类。

1.第一次采用@EnableAutoConfiguration注解排除

image.png 启动如下: image.png MybatisAutoConfiguration本身就存在org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中,而kui-common-datasource模块又被添加到system业务模块中,导致了循环导入问题。
排除一种,因为路径不同,然后我希望业务模块引入kui-common-datasource模块就可以在配置文件中添加数据库,不同修改启动类代码,也不需要添加注解什么的,所以我不能排除imports文件方式,但是怎么排除呢,难道每一个业务模块添加了该模块都在@SpringBootApplication注解上去排除吗?最好模块内部自己就解决这个问题。

2.分析主要还是EnableAutoConfiguration这个注解

主要是AutoConfigurationImportSelector这个类 image.png image.png 进入getExclusions这个方法看看 image.png 可以发现有三处来源,第一二处来源于注解,但是还有第三处,这里查找了环境配置中的属性spring.autoconfigure.exclude image.png

3.向环境中添加值

现在知道还有第三处来源,现在问题是如何向environment添加了。

image.png 这个和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

启动,这次就成功了。