自我救赎之路—(springboot 配置多种数据源)

来源:互联网 发布:网络黑侠所有的书 编辑:程序博客网 时间:2024/05/17 23:33

配置连接多个数据库

说明,最近要做一个数据处理服务器,一方面是要调用数据服务器自己的数据库,另一方面是要调用业务数据库. .net分分种钟搞定,但是这个springboot 不太了解,说真的,我是在网上早的,但还是整理一下。

1. 先来贴pom.xml 文件内容:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>    <groupId>com.bom</groupId>    <artifactId>dataservice</artifactId>    <version>0.0.1-SNAPSHOT</version>    <packaging>jar</packaging>    <name>dataservice</name>    <description>Demo project for Spring Boot</description>    <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>1.5.8.RELEASE</version>        <relativePath/> <!-- lookup parent from repository -->    </parent>    <properties>        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>        <java.version>1.8</java.version>        <!-- mysql驱动版本号 -->        <mysql-driver.version>5.1.29</mysql-driver.version>    </properties>    <dependencies>        <!--<dependency>            <groupId>org.mybatis.spring.boot</groupId>            <artifactId>mybatis-spring-boot-starter</artifactId>            <version>1.3.1</version>        </dependency>-->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web-services</artifactId>        </dependency>        <!--<dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <scope>runtime</scope>        </dependency>-->        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>${mysql-driver.version}</version>            <scope>runtime</scope>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>        <dependency>            <groupId>io.springfox</groupId>            <artifactId>springfox-swagger2</artifactId>            <version>2.6.1</version>        </dependency>        <dependency>            <groupId>io.springfox</groupId>            <artifactId>springfox-swagger-ui</artifactId>            <version>2.6.1</version>        </dependency>        <dependency>            <groupId>io.springfox</groupId>            <artifactId>springfox-staticdocs</artifactId>            <version>2.6.1</version>        </dependency>        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>fastjson</artifactId>            <version>1.2.8</version>        </dependency>        <dependency>            <groupId>org.springframework.restdocs</groupId>            <artifactId>spring-restdocs-mockmvc</artifactId>            <exclusions>                <exclusion>                    <artifactId>spring-test</artifactId>                    <groupId>org.springframework</groupId>                </exclusion>            </exclusions>            <scope>test</scope>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-test-autoconfigure</artifactId>        </dependency>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>        </dependency>        <dependency>            <groupId>org.apache.httpcomponents</groupId>            <artifactId>httpcore</artifactId>            <version>4.4.6</version>        </dependency>        <dependency>            <groupId>antlr</groupId>            <artifactId>antlr</artifactId>            <version>2.7.7</version>        </dependency>        <dependency>            <groupId>org.apache.httpcomponents</groupId>            <artifactId>httpclient</artifactId>            <version>4.5.2</version>        </dependency>        <dependency>            <groupId>org.apache.httpcomponents</groupId>            <artifactId>httpcore</artifactId>            <version>4.4.6</version>        </dependency>        <dependency>            <groupId>org.apache.httpcomponents</groupId>            <artifactId>httpclient</artifactId>            <version>4.5.2</version>        </dependency>        <dependency>            <groupId>org.apache.httpcomponents</groupId>            <artifactId>httpcore</artifactId>            <version>4.4.6</version>        </dependency>        <!-- springjpa            springjpa中带有自带的tomcat 数据连接池;           在代码中我们也需要用到.      -->        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-data-jpa</artifactId>        </dependency>        <dependency>            <groupId>ant</groupId>            <artifactId>ant</artifactId>            <version>1.6.5</version>        </dependency>    </dependencies>    <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>            </plugin>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-surefire-plugin</artifactId>                <configuration>                    <includes>                        <include>**/*Documentation.java</include>                    </includes>                </configuration>            </plugin>            <plugin>                <groupId>org.asciidoctor</groupId>                <artifactId>asciidoctor-maven-plugin</artifactId>                <version>1.5.3</version>                <!-- Configure generic document generation settings -->                <configuration>                    <sourceDirectory>${project.basedir}/docs/asciidoc</sourceDirectory>                    <sourceDocumentName>index.adoc</sourceDocumentName>                    <attributes>                        <doctype>book</doctype>                        <toc>left</toc>                        <toclevels>3</toclevels>                        <numbered></numbered>                        <hardbreaks></hardbreaks>                        <sectlinks></sectlinks>                        <sectanchors></sectanchors>                        <generated>${project.build.directory}/asciidoc</generated>                    </attributes>                </configuration>                <!-- Since each execution can only handle one backend, run                     separate executions for each desired output type -->                <executions>                    <execution>                        <id>output-html</id>                        <phase>test</phase>                        <goals>                            <goal>process-asciidoc</goal>                        </goals>                        <configuration>                            <backend>html5</backend>                            <!--<outputDirectory>${project.basedir}/docs/asciidoc/html</outputDirectory>-->                        </configuration>                    </execution>                </executions>            </plugin>        </plugins>    </build></project>

2. 再来看帖出来的代码:

a. DynamicDataSource

package com.bom.dataservice.config;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/** * Created by chenwangming on 2017/11/14. */public class DynamicDataSource  extends AbstractRoutingDataSource {    /*       *代码中的determineCurrentLookupKey方法取得一个字符串,       *该字符串将与配置文件中的相应字符串进行匹配以定位数据源,配置文件,即applicationContext.xml文件中需要要如下代码:(non-Javadoc)       * @seeorg.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey()       */    @Override    protected Object determineCurrentLookupKey() {              /*               * DynamicDataSourceContextHolder代码中使用setDataSourceType               *设置当前的数据源,在路由类中使用getDataSourceType进行获取,               * 交给AbstractRoutingDataSource进行注入使用。               */        return DynamicDataSourceContextHolder.getDataSourceType();    }}

b. DynamicDataSourceAspect

package com.bom.dataservice.config;/** * Created by chenwangming on 2017/11/14. */import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;/** *切换数据源Advice *@author 陈王明 *@version v.0.1 */@Aspect@Order(-10)//保证该AOP在@Transactional之前执行@Componentpublic class DynamicDataSourceAspect {    /*           * @Before("@annotation(ds)")           *的意思是:           *           * @Before:在方法执行之前进行执行:           * @annotation(targetDataSource):           *会拦截注解targetDataSource的方法,否则不拦截;           */    @Before("@annotation(targetDataSource)")    public void changeDataSource(JoinPoint point, TargetDataSource targetDataSource) throws Throwable {        //获取当前的指定的数据源;        String dsId = targetDataSource.value();        //如果不在我们注入的所有的数据源范围之内,那么输出警告信息,系统自动使用默认的数据源。        if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {            System.err.println("数据源[{}]不存在,使用默认数据源 > {}"+targetDataSource.value()+point.getSignature());        } else {            System.out.println("UseDataSource : {} > {}"+targetDataSource.value()+point.getSignature());            //找到的话,那么设置到动态数据源上下文中。            DynamicDataSourceContextHolder.setDataSourceType(targetDataSource.value());        }    }    @After("@annotation(targetDataSource)")    public void restoreDataSource(JoinPoint point, TargetDataSource targetDataSource) {        System.out.println("RevertDataSource : {} > {}"+targetDataSource.value()+point.getSignature());        //方法执行完毕之后,销毁当前数据源信息,进行垃圾回收。        DynamicDataSourceContextHolder.clearDataSourceType();    }}

c. DynamicDataSourceContextHolder

package com.bom.dataservice.config;import java.util.ArrayList;import java.util.List;/** * Created by chenwangming on 2017/11/14. */public class DynamicDataSourceContextHolder {    /*        *当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,        *所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。        */    private static final ThreadLocal<String>contextHolder = new ThreadLocal<String>();    /*     *管理所有的数据源id;     *主要是为了判断数据源是否存在;     */    public static List<String> dataSourceIds =new ArrayList<String>();    /**     *使用setDataSourceType设置当前的     *@param dataSourceType     */    public static void setDataSourceType(String dataSourceType) {        contextHolder.set(dataSourceType);    }    public static String getDataSourceType() {        return contextHolder.get();    }    public static void clearDataSourceType() {        contextHolder.remove();    }    /**     *判断指定DataSrouce当前是否存在     *     *@param dataSourceId     *@return     *@author 陈王明     *@create  2017年11月14日     */    public static boolean containsDataSource(String dataSourceId){        return dataSourceIds.contains(dataSourceId);    }}

d. DynamicDataSourceRegister

package com.bom.dataservice.config;import java.util.HashMap;import java.util.Map;import javax.sql.DataSource;import org.springframework.beans.MutablePropertyValues;import org.springframework.beans.PropertyValues;import org.springframework.beans.factory.support.BeanDefinitionRegistry;import org.springframework.beans.factory.support.GenericBeanDefinition;import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;import org.springframework.boot.bind.RelaxedDataBinder;import org.springframework.boot.bind.RelaxedPropertyResolver;import org.springframework.context.EnvironmentAware;import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;import org.springframework.core.convert.ConversionService;import org.springframework.core.convert.support.DefaultConversionService;import org.springframework.core.env.Environment;import org.springframework.core.type.AnnotationMetadata;/** * Created by chenwangming on 2017/11/14. */public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware{    //如配置文件中未指定数据源类型,使用该默认值    private static final Object DATASOURCE_TYPE_DEFAULT ="org.apache.tomcat.jdbc.pool.DataSource";    private ConversionService conversionService = new DefaultConversionService();    private PropertyValues dataSourcePropertyValues;    // 默认数据源    private DataSource defaultDataSource;    private Map<String, DataSource> customDataSources = new HashMap<String, DataSource>();    /**     *加载多数据源配置     */    @Override    public void setEnvironment(Environment environment) {        System.out.println("DynamicDataSourceRegister.setEnvironment()");        initDefaultDataSource(environment);        initCustomDataSources(environment);    }    /**     *加载主数据源配置.     *@param env     */    private void initDefaultDataSource(Environment env){        // 读取主数据源        RelaxedPropertyResolver propertyResolver =new RelaxedPropertyResolver(env,"spring.datasource.");        Map<String,Object>dsMap = new HashMap<String, Object>();        dsMap.put("type", propertyResolver.getProperty("type"));        dsMap.put("driverClassName", propertyResolver.getProperty("driverClassName"));        dsMap.put("url", propertyResolver.getProperty("url"));        dsMap.put("username", propertyResolver.getProperty("username"));        dsMap.put("password", propertyResolver.getProperty("password"));        //创建数据源;        defaultDataSource =buildDataSource(dsMap);        dataBinder(defaultDataSource,env);    }    /**     *初始化更多数据源     *     *@author 陈王明     *@create 2017年11月14日     */    private 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 +".");            DataSource ds = buildDataSource(dsMap);            customDataSources.put(dsPrefix, ds);            dataBinder(ds,env);        }    }    /**     *创建datasource.     *@param dsMap     *@return     */    @SuppressWarnings("unchecked")    public DataSource buildDataSource(Map<String, Object>dsMap) {        Object type =dsMap.get("type");        if (type ==null){            type = DATASOURCE_TYPE_DEFAULT;//默认DataSource        }        Class<? extends DataSource>dataSourceType;        try {            dataSourceType = (Class<? extends DataSource>)Class.forName((String)type);            String driverClassName =dsMap.get("driverClassName").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;    }    /**     *为DataSource绑定更多数据     *@param dataSource     *@param env     */    private void dataBinder(DataSource dataSource, Environment env){        RelaxedDataBinder dataBinder =new RelaxedDataBinder(dataSource);        dataBinder.setConversionService(conversionService);        dataBinder.setIgnoreNestedProperties(false);//false        dataBinder.setIgnoreInvalidFields(false);//false        dataBinder.setIgnoreUnknownFields(true);//true        if(dataSourcePropertyValues ==null){            Map<String, Object>rpr = new RelaxedPropertyResolver(env,"spring.datasource").getSubProperties(".");            Map<String, Object>values = new HashMap<>(rpr);            // 排除已经设置的属性            values.remove("type");            values.remove("driverClassName");            values.remove("url");            values.remove("username");            values.remove("password");            dataSourcePropertyValues = new MutablePropertyValues(values);        }        dataBinder.bind(dataSourcePropertyValues);    }    @Override    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry) {        System.out.println("DynamicDataSourceRegister.registerBeanDefinitions()");        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();        //添加属性:AbstractRoutingDataSource.defaultTargetDataSource        mpv.addPropertyValue("defaultTargetDataSource",defaultDataSource);        mpv.addPropertyValue("targetDataSources",targetDataSources);        registry.registerBeanDefinition("dataSource",beanDefinition);    }}

e. TargetDataSource

package com.bom.dataservice.config;/** * Created by chenwangming on 2017/11/14. */import java.lang.annotation.*;/** *在方法上使用,用于指定使用哪个数据源 *@author 陈王明 *@version v.0.1 */@Target({ ElementType.METHOD, ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface TargetDataSource {    String value();}

3. 最后再启动类中注册动态数据源类

package com.bom.dataservice;import com.bom.dataservice.config.DynamicDataSourceRegister;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Import;@SpringBootApplication@Import({DynamicDataSourceRegister.class}) //这个就是注册类public class DataserviceApplication {    public static void main(String[] args) {        SpringApplication.run(DataserviceApplication.class, args);    }}

总结一下,到这里就搞定了,因为能力有限,描述不足,当保证能用,后期在来补充。


经历过黑暗,才有对光明的渴望;经历过风雨,才懂得阳光的温暖;经历过沧桑,才拥有温柔的内心;经历人生最好的成长。

今天对面坐了一位美女,心情很激动,导致我没有用心去写博客。

共同学习,共同进步,技术交流群:210470210

原创粉丝点击