溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

springboot動(dòng)態(tài)數(shù)據(jù)源的使用

發(fā)布時(shí)間:2020-06-06 16:17:38 來源:億速云 閱讀:904 作者:Leah 欄目:編程語言

這篇文章運(yùn)用了實(shí)例代碼展示springboot動(dòng)態(tài)數(shù)據(jù)源的使用方法,代碼非常詳細(xì),可供感興趣的小伙伴們參考借鑒,希望對(duì)大家有所幫助。

一.應(yīng)用案例

我們的數(shù)據(jù)庫A為主庫,其他數(shù)據(jù)庫配置在主庫中,從庫B,C,D的數(shù)量是不固定的,會(huì)根據(jù)業(yè)務(wù)的需要?jiǎng)討B(tài)的把配置寫入到主庫中并動(dòng)態(tài)在創(chuàng)建新的數(shù)據(jù)庫,也就是說在項(xiàng)目中我們只需要配置主庫的數(shù)據(jù)源,其他從庫都需要從主庫中讀出配置并動(dòng)態(tài)創(chuàng)建數(shù)據(jù)源,動(dòng)態(tài)的注入到Spring容器中,在使用的時(shí)候動(dòng)態(tài)的切換數(shù)據(jù)源以實(shí)現(xiàn)相應(yīng)的功能邏輯

二.環(huán)境配置

Springboot:2.0.4
Mybatis-plus:3.0.7.1
JDK:1.8

三.方案實(shí)踐

1.項(xiàng)目啟動(dòng)類修改

在啟動(dòng)類添加@Import({DynamicDataSourceRegister.class})注解用于代替默認(rèn)的數(shù)據(jù)源配置

2.代碼結(jié)構(gòu)

代碼結(jié)構(gòu)如下:
springboot動(dòng)態(tài)數(shù)據(jù)源的使用

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

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

    /**
     * 取得存儲(chǔ)在靜態(tài)變量中的ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }

    /**
     * 從靜態(tài)變量ApplicationContext中取得Bean, 自動(dòng)轉(zhuǎn)型為所賦值對(duì)象的類型.
     */
    public static <T> T getBean(String name) {
        checkApplicationContext();
        if (applicationContext.containsBean(name)) {
            return (T) applicationContext.getBean(name);
        }
        return null;
    }

    /**
     * 從靜態(tài)變量ApplicationContext中取得Bean, 自動(dòng)轉(zhuǎn)型為所賦值對(duì)象的類型.
     */
    public static <T> T getBean(Class<T> clazz) {
        checkApplicationContext();
        return (T) applicationContext.getBeansOfType(clazz);
    }

    private static void checkApplicationContext() {
        if (applicationContext == null)
            throw new IllegalStateException("applicaitonContext未注入,請(qǐng)?jiān)赼pplicationContext.xml中定義SpringContextUtil");
    }
    public synchronized static void registerSingletonBean(String beanName,Class clzz,Map<String,Object> 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<String,Object> 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<String, Object> transBean2Map(Object obj) {
    if(obj == null){
    return null;
    }
    Map<String, Object> 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對(duì)應(yīng)的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<String,DataSource> customDataSources){
        Map<Object,Object> customDS=new HashMap<Object, Object>();
        customDS.putAll(customDataSources);
        setTargetDataSources(customDS);
        afterPropertiesSet();
    }
}
public class DynamicDataSourceContextHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
    public static List<String> 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當(dāng)前是否存在
     */
    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);

    //默認(rèn)數(shù)據(jù)源
    public static DataSource defaultDataSource;
    //用戶自定義數(shù)據(jù)源
    public static Map<String, DataSource> 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) {
        // 讀取主數(shù)據(jù)源
        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<String, Object> 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<Object, Object> targetDataSources = new HashMap<Object, Object>();
        //添加默認(rèn)數(shù)據(jù)源
        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<String,DataSource> oldTargetDataSource=(Map<String,DataSource>) propertyValue.getValue();

        String newUrl=firstStr+dataSourceType+secondStr;

        Map<String, Object> 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<Object,Object> targetDataSources){
        //創(chuàng)建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<String, Object> dataSourceMap) {
        try {
            Object type = dataSourceMap.get("type");
            Class<? extends DataSource> dataSourceType;
            dataSourceType = (Class<? extends DataSource>) 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.使用實(shí)例

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

在setDataSourceType的時(shí)候判斷是否存在此數(shù)據(jù)源,如果存在就直接切換,不存在就動(dòng)態(tài)創(chuàng)建并加入到Spring容器中,從而實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建數(shù)據(jù)源的目的

關(guān)于springboot動(dòng)態(tài)數(shù)據(jù)源的使用就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI