springboot动态数据源的使用

这篇文章运用了实例代码展示springboot动态数据源的使用方法,代码非常详细,可供感兴趣的小伙伴们参考借鉴,希望对大家有所帮助。

创新互联建站,为您提供网站建设公司成都网站制作、网站营销推广、网站开发设计,对服务成都宣传片制作等多个行业拥有丰富的网站建设及推广经验。创新互联建站网站建设公司成立于2013年,提供专业网站制作报价服务,我们深知市场的竞争激烈,认真对待每位客户,为客户提供赏心悦目的作品。 与客户共同发展进步,是我们永远的责任!

一.应用案例

我们的数据库A为主库,其他数据库配置在主库中,从库B,C,D的数量是不固定的,会根据业务的需要动态的把配置写入到主库中并动态在创建新的数据库,也就是说在项目中我们只需要配置主库的数据源,其他从库都需要从主库中读出配置并动态创建数据源,动态的注入到Spring容器中,在使用的时候动态的切换数据源以实现相应的功能逻辑

二.环境配置

Springboot:2.0.4
Mybatis-plus:3.0.7.1
JDK:1.8

三.方案实践

1.项目启动类修改

在启动类添加@Import({DynamicDataSourceRegister.class})注解用于代替默认的数据源配置

2.代码结构

代码结构如下:
springboot动态数据源的使用

@Component
public class ApplicationContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextUtil.applicationContext = applicationContext;
    }

    /**
     * 取得存储在静态变量中的ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }

    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    public static  T getBean(String name) {
        checkApplicationContext();
        if (applicationContext.containsBean(name)) {
            return (T) applicationContext.getBean(name);
        }
        return null;
    }

    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    public static  T getBean(Class clazz) {
        checkApplicationContext();
        return (T) applicationContext.getBeansOfType(clazz);
    }

    private static void checkApplicationContext() {
        if (applicationContext == null)
            throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextUtil");
    }
    public synchronized static void registerSingletonBean(String beanName,Class clzz,Map original) {
        checkApplicationContext();
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) ApplicationContextUtil.getApplicationContext().getAutowireCapableBeanFactory();
        if(beanFactory.containsBean(beanName)){
            removeBean(beanName);
        }
        GenericBeanDefinition definition = new GenericBeanDefinition();
        //类class
        definition.setBeanClass(clzz);
        //属性赋值
        definition.setPropertyValues(new MutablePropertyValues(original));
        //注册到spring上下文
        beanFactory.registerBeanDefinition(beanName, definition);
    }
    public synchronized static void registerSingletonBean(String beanName, Object obj, Map original) {
        checkApplicationContext();
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) ApplicationContextUtil.getApplicationContext().getAutowireCapableBeanFactory();
        if(beanFactory.containsBean(beanName)){
            removeBean(beanName);
        }
        GenericBeanDefinition definition = new GenericBeanDefinition();
        //类class
        definition.setBeanClass(obj.getClass());
        //属性赋值
        definition.setPropertyValues(new MutablePropertyValues(original));
        //注册到spring上下文
        beanFactory.registerBeanDefinition(beanName, definition);
    }
    public synchronized static void registerSingletonBean(String beanName,Object obj) {
        registerSingletonBean(beanName,obj,BeanUtils.transBean2Map(obj));
    }
    /**
     * 删除spring中管理的bean
     * @param beanName
     */
    public static void removeBean(String beanName){
        ApplicationContext ctx = ApplicationContextUtil.getApplicationContext();
        DefaultListableBeanFactory acf = (DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory();
        if(acf.containsBean(beanName)) {
            acf.removeBeanDefinition(beanName);
        }
    }
}
public class BeanUtils {
public static Map transBean2Map(Object obj) {
    if(obj == null){
    return null;
    }
    Map map = new HashMap<>();
    try {
         BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
         PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                // 过滤class属性
                if (!key.equals("class")) {
                // 得到property对应的getter方法
                Method getter = property.getReadMethod();
                Object value = getter.invoke(obj);
                map.put(key, value);
                }
            }
         } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
         }
        return map;
    }
}
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }

    public  void updateTargetDataSource(Map customDataSources){
        Map customDS=new HashMap();
        customDS.putAll(customDataSources);
        setTargetDataSources(customDS);
        afterPropertiesSet();
    }
}
public class DynamicDataSourceContextHolder {
    private static final ThreadLocal contextHolder = new ThreadLocal<>();
    public static List dataSourceIds = new ArrayList<>();

    public static String getDataSourceType() {
        return contextHolder.get();
    }

    public static void setDataSourceType(String dataSourceType) {
        if(!containsDataSource(dataSourceType)){
            DynamicDataSourceRegister.addSlaveDataSource(dataSourceType);
        }
        contextHolder.set(dataSourceType);
    }

    public static void clearDataSourceType() {
        contextHolder.remove();
    }

    /**
     * 判断指定DataSrouce当前是否存在
     */
    public static boolean containsDataSource(String dataSourceId) {
        return dataSourceIds.contains(dataSourceId);
    }
}
public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);

    //默认数据源
    public static DataSource defaultDataSource;
    //用户自定义数据源
    public static Map slaveDataSources = new HashMap<>();

    public static BeanDefinitionRegistry beanDefinitionRegistry=null;

    public static String driverName;
    public static String userName;
    public static String password;
    public static String type;
    public static String url;

    @Override
    public  void setEnvironment(Environment environment) {
        initDefaultDataSource(environment);
    }

    private void initDefaultDataSource(Environment env) {
        // 读取主数据源
        driverName=env.getProperty("spring.datasource.driver-class-name");
        userName=env.getProperty("spring.datasource.username");
        password=env.getProperty("spring.datasource.password");
        type=env.getProperty("spring.datasource.type");
        url=env.getProperty("spring.datasource.url");

        Constant.defaultDbName="a";

        Map dsMap = new HashMap<>();
        dsMap.put("driver",driverName);
        dsMap.put("url",url);
        dsMap.put("username",userName);
        dsMap.put("password",password);
        dsMap.put("type",type);
        defaultDataSource = buildDataSource(dsMap);
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
        Map targetDataSources = new HashMap();
        //添加默认数据源
        targetDataSources.put("dataSource", this.defaultDataSource);

        this.beanDefinitionRegistry=beanDefinitionRegistry;
        beanDefinitionRegistry(defaultDataSource,targetDataSources);
        logger.info("Dynamic DataSource Registry");
    }

    public static void addSlaveDataSource(String dataSourceType){
        BeanDefinition beanDefinition=beanDefinitionRegistry.getBeanDefinition("dataSource");
        PropertyValue propertyValue=beanDefinition.getPropertyValues().getPropertyValue("targetDataSources");
        Map oldTargetDataSource=(Map) propertyValue.getValue();

        String newUrl=firstStr+dataSourceType+secondStr;

        Map dsMap = new HashMap<>();
        dsMap.put("driver",driverName);
        dsMap.put("url",newUrl);
        dsMap.put("username",userName);
        dsMap.put("password",password);
        dsMap.put("type",type);
        DataSource ds = buildDataSource(dsMap);

        oldTargetDataSource.put(dataSourceType,ds);
        DynamicDataSource dynamicDataSource =ApplicationContextUtil.getBean("dataSource");
        dynamicDataSource.updateTargetDataSource(oldTargetDataSource);
        DynamicDataSourceContextHolder.dataSourceIds.add(dataSourceType);
    }

    public void beanDefinitionRegistry(DataSource defaultDataSource,Map targetDataSources){
        //创建DynamicDataSource
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(DynamicDataSource.class);
        beanDefinition.setSynthetic(true);
        MutablePropertyValues mpv = beanDefinition.getPropertyValues();
        mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
        if(targetDataSources.size()>0){
            mpv.addPropertyValue("targetDataSources", targetDataSources);
        }
        //注册 - BeanDefinitionRegistry
        beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
    }

    public static DataSource buildDataSource(Map dataSourceMap) {
        try {
            Object type = dataSourceMap.get("type");
            Class dataSourceType;
            dataSourceType = (Class) Class.forName((String) type);
            String driverClassName = dataSourceMap.get("driver").toString();
            String url = dataSourceMap.get("url").toString();
            String username = dataSourceMap.get("username").toString();
            String password = dataSourceMap.get("password").toString();
            // 自定义DataSource配置
            DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
                    .username(username).password(password).type(dataSourceType);
            return factory.build();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}

3.使用实例

DynamicDataSourceContextHolder.setDataSourceType("B");
Integer lProductUv=dataVisitCollectionMapper.getProductUv(dDate);
DynamicDataSourceContextHolder.setDataSourceType(Constant.defaultDbName);

在setDataSourceType的时候判断是否存在此数据源,如果存在就直接切换,不存在就动态创建并加入到Spring容器中,从而实现动态创建数据源的目的

关于springboot动态数据源的使用就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。


当前标题:springboot动态数据源的使用
文章URL:http://azwzsj.com/article/gspjco.html