SpringBoot的多数据源配置

来源:互联网 发布:淘宝网孕妇装春装 编辑:程序博客网 时间:2024/04/28 00:03

在项目中需要在不同的IP里的数据库获取数据,所以要求要可以灵活的指定具体要操作的数据库。
主要使用的框架是spring-boot+mybatis等。

一:先将maven项目配置好(略);
二:springboot的启动类:

import org.apache.log4j.Logger;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Import;@Import(DynamicDataSourceRegister.class)@SpringBootApplicationpublic class Application {    private static Logger logger = Logger.getLogger(Application.class);    public static void main(String[] args) {        SpringApplication.run(Application.class, args);    }}

三:SpringBoot多数据源的配置:
1.springboot的数据源属性文件:

//默认的数据源spring.datasource.url=jdbc:mysql://138.0.0.1:4545/test1spring.datasource.username=rootspring.datasource.password=rootspring.datasource.driver-class-name=com.mysql.jdbc.Driver//配置的第二个数据源custom.datasource.names=test2custom.datasource.new.url=jdbc:mysql://138.0.0.1:5656/test2custom.datasource.new.username=rootcustom.datasource.new.password=rootcustom.datasource.new.driver-class-name=com.mysql.jdbc.Driver

2 .编写一个动态数据源类:

import java.util.ArrayList;import java.util.List;/** * @ClassName DynamicDataSourceContextHolder * @Description 判断当前数据源是否存在(上下文) */public class DynamicDataSourceContextHolder {    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();    public static List<String> dataSourceIds = new ArrayList<>();     //使用setDataSourceType设置当前的    public static void setDataSourceType(String dataSourceType) {        contextHolder.set(dataSourceType);    }    public static String getDataSourceType() {        return contextHolder.get();    }    public static void clearDataSourceType() {        contextHolder.remove();    }     //判断指定DataSrouce当前是否存在    public static boolean containsDataSource(String dataSourceId){        return dataSourceIds.contains(dataSourceId);    }}

3.动态数据源:

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/** * @ClassName DynamicDataSource */public class DynamicDataSource extends AbstractRoutingDataSource {//设置当前的数据源,在路由类中使用getDataSourceType进行获取,//  交给AbstractRoutingDataSource进行注入使用。    @Override    protected Object determineCurrentLookupKey() {        // TODO Auto-generated method stub        return DynamicDataSourceContextHolder.getDataSourceType();    } }

4.指定数据源注解类:

/** * @ClassName DynamicDataSourceAspect * @Description 切换数据源Advice */@Aspect@Order(-1)//保证该AOP在@Transactional之前执行@Componentpublic class DynamicDataSourceAspect {    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);    @Before("@annotation(Source)")    public void changeDataSource(JoinPoint point, TargetDataSource Source) throws Throwable {        String dsId = Source.name();        if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {            logger.error("数据源[{}]不存在,使用默认数据源 > {}", ds.name(), point.getSignature());        } else {            logger.debug("Use DataSource : {} > {}", Source.name(), point.getSignature());            DynamicDataSourceContextHolder.setDataSourceType(ds.name());        }    }    @After("@annotation(Source)")    public void restoreDataSource(JoinPoint point, TargetDataSource Source) {        logger.debug("Revert DataSource : {} > {}", Source.name(), point.getSignature()); //方法执行完毕之后,销毁当前数据源信息,进行垃圾回收。        DynamicDataSourceContextHolder.clearDataSourceType();    }}

5.注册多数据源:
以上都是动态数据源在注入的时候使用的代码,其实很重要的一部分代码就是注册我们在application.properties配置的多数据源;

/** * @ClassName DynamicDataSourceRegister * @Description 动态数据源注册 */public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);    // 如配置文件中未指定数据源类型,使用该默认值    private static final Object DATASOURCE_TYPE_DEFAULT = "org.apache.tomcat.jdbc.pool.DataSource";    // private static final Object DATASOURCE_TYPE_DEFAULT =    // "com.zaxxer.hikari.HikariDataSource";    // 数据源    private DataSource defaultDataSource;    private Map<String,DataSource> customDataSources = new HashMap<>();    /**     * 创建DataSource     *     * @param type     * @param driverClassName     * @param url     * @param username     * @param password     * @return     */    @SuppressWarnings("unchecked")    public DataSource buildDataSource(Map<String,Object> dsMap) {        try {            Object type = dsMap.get("type");            if (type == null)                type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource            Class dataSourceType;            dataSourceType = (Class) Class.forName((String) type);            String driverClassName = dsMap.get("driver-class-name").toString();            String url = dsMap.get("url").toString();            String username = dsMap.get("username").toString();            String password = dsMap.get("password").toString();            DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)                    .username(username).password(password).type(dataSourceType);            return factory.build();        } catch (ClassNotFoundException e) {            e.printStackTrace();        }        return null;    }    /**     * 加载多数据源配置     */    @Override    public void setEnvironment(Environment env) {        initDefaultDataSource(env);        initCustomDataSources(env);    }    /**     * 初始化主数据源     *     */    public void initDefaultDataSource(Environment env) {        // 读取主数据源        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "spring.datasource.");        Map<String,Object> dsMap = new HashMap<>();        dsMap.put("type", propertyResolver.getProperty("type"));        dsMap.put("driver-class-name", propertyResolver.getProperty("driver-class-name"));        dsMap.put("url", propertyResolver.getProperty("url"));        dsMap.put("username", propertyResolver.getProperty("username"));        dsMap.put("password", propertyResolver.getProperty("password"));        defaultDataSource = buildDataSource(dsMap);    }    /**     * 初始化更多数据源     *     */    public void initCustomDataSources(Environment env) {        // 读取配置文件获取更多数据源,也可以通过defaultDataSource读取数据库获取更多数据源        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, "custom.datasource.");        String dsPrefixs = propertyResolver.getProperty("names");        for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源            Map<String,Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");            customDataSources.put(dsPrefix, buildDataSource(dsMap));        }    }    @Override    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {        // TODO Auto-generated method stub        Map<Object,Object> targetDataSources = new HashMap<Object,Object>();        // 将主数据源添加到更多数据源中        targetDataSources.put("dataSource", defaultDataSource);        DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");        // 添加更多数据源        targetDataSources.putAll(customDataSources);        for (String key : customDataSources.keySet()) {            DynamicDataSourceContextHolder.dataSourceIds.add(key);        }        // 创建DynamicDataSource        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();        beanDefinition.setBeanClass(DynamicDataSource.class);        beanDefinition.setSynthetic(true);        MutablePropertyValues mpv = beanDefinition.getPropertyValues();        mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);        mpv.addPropertyValue("targetDataSources", targetDataSources);        registry.registerBeanDefinition("dataSource", beanDefinition);        logger.info("Dynamic DataSource Registry");    }}

6.添加使用的标签:

import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.Target;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.ElementType;/** * @ClassName TargetDataSource * @Description 在方法上使用,用于指定使用哪个数据源 */@Target({ ElementType.METHOD, ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface TargetDataSource {    String name();    }

现在已经完成了多数据源的配置,现在就是使用了;
写好mybatis的查询方法后,调用如下:

@Override    public void slselecttest1() {        // TODO Auto-generated method stub         //mybatis查询 test1数据库的方法        CommunityAnalysisDao.slselecttest1();    }    @Override    @TargetDataSource(name="test2")//test2是你数据源配置属性文件的names    public void slselecttest2() {        // TODO Auto-generated method stub        //mybatis查询 test2数据库的方法        CommunityAnalysisDao.slselecttest2();    }   

这样就可以跨库查询了。

本文参考:http://blog.csdn.net/catoop/article/details/50575038
http://blog.csdn.net/linxingliang/article/details/52324937

0 0
原创粉丝点击