Spring数据源自动配置

x单个项目涉及多个数据库时,我们需要做很多的数据库配置之外,还需要写很多的代码来配置数据源,通常这样的代码是具有一定重复性的,因此希望能够简单的配置。

为了一次编码多次使用,我们需要手动的把数据源交给Spring管理,因此我们需要注册数据源信息。

通过实现ImportBeanDefinitionRegistrar来注册bean,通过实现EnvironmentAware获取配置信息。

数据库配置信息

####sakila db
spring.datasource.sakila.url=jdbc:mysql://localhost:3306/sakila?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true
spring.datasource.sakila.username=root
spring.datasource.sakila.password=root
spring.datasource.sakila.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.sakila.initialSize=1
spring.datasource.sakila.maxIdle=2
spring.datasource.sakila.minIdle=1

####library db
spring.datasource.library.url=jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true
spring.datasource.library.username=root
spring.datasource.library.password=root
spring.datasource.library.driverClassName=com.mysql.cj.jdbc.Driver

####comm info
spring.datasource.comm.names=sakila,library,schema
spring.datasource.comm.primary=library
spring.datasource.comm.type=org.apache.commons.dbcp.BasicDataSource

####pool info
spring.datasource.pool.initialSize=1
spring.datasource.pool.maxIdle=2
spring.datasource.pool.minIdle=1

DataSourceRegister: 实现了ImportBeanDefinitionRegistrar,EnvironmentAware

package com.mutil.transaction.config;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

/**
 * Created by WuTing on 2017/12/8.
 */
public class DataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
    private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceRegister.class);
    private static final BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
    private static final String[] DATA_SOURCE_TYPE_NAMES = {"org.apache.tomcat.jdbc.pool.DataSource",
        "com.zaxxer.hikari.HikariDataSource", "org.apache.commons.dbcp.BasicDataSource",
        "org.apache.commons.dbcp2.BasicDataSource"};
    private static Map<String, Map<String, Object>> dataSourceMap = new HashMap<>();
    private static Map<String, Object> commProperties = new HashMap<>();
    private static Map<String, Object> poolProperties = new HashMap<>();
    private static String primary;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        this.registerDataSources(registry);

        this.registerDynamicDataSource(registry);
    }

    private void registerDataSources(BeanDefinitionRegistry registry) {
        dataSourceMap.forEach((dataSourceName, properties) -> {
            maybeGetDriverClassName(properties);
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setSynthetic(true);
            beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);

            MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
            propertyValues.addPropertyValues(poolProperties);
            propertyValues.addPropertyValues(properties);

            dataSourceName = this.getDataSourceName(registry, dataSourceName, beanDefinition);
            if (primary.equals(dataSourceName)) {
                beanDefinition.setPrimary(true);
            }

            this.printDataSourceConfigInfo(dataSourceName, beanDefinition);
            beanDefinition.setBeanClass(this.findType(MapUtils.getString(properties, "type")));
            registry.registerBeanDefinition(dataSourceName, beanDefinition);

        });
    }

    private void registerDynamicDataSource(BeanDefinitionRegistry registry) {
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setSynthetic(true);
        beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
        beanDefinition.setBeanClass(DynamicDataSource.class);
        ConstructorArgumentValues args = new ConstructorArgumentValues();
        args.addIndexedArgumentValue(0, primary);
        beanDefinition.setConstructorArgumentValues(args);
        registry.registerBeanDefinition("dataSource", beanDefinition);
    }

    private void printDataSourceConfigInfo(String dataSourceName, GenericBeanDefinition beanDefinition) {
        System.out.println("\n");
        LOGGER.warn(dataSourceName);
        Arrays.stream(beanDefinition.getPropertyValues().getPropertyValues())
            .forEach((property) -> LOGGER.warn(property.getName() + " --> " + property.getValue()));
        LOGGER.warn("primary --> " + beanDefinition.isPrimary());
    }

    private String getDataSourceName(BeanDefinitionRegistry registry, String dataSourceName,
        GenericBeanDefinition beanDefinition) {
        if (StringUtils.isEmpty(dataSourceName)) {
            dataSourceName = beanNameGenerator.generateBeanName(beanDefinition, registry);
        }
        return dataSourceName;
    }

    @Override
    public void setEnvironment(Environment environment) {
        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(environment, "spring.datasource.");
        commProperties.putAll(propertyResolver.getSubProperties("comm."));
        poolProperties.putAll(propertyResolver.getSubProperties("pool."));
        this.initDataSourceMap(propertyResolver);
        this.initPrimary();
    }

    private void initDataSourceMap(RelaxedPropertyResolver propertyResolver) {
        String names = MapUtils.getString(commProperties, "names");
        if (StringUtils.isNotEmpty(names)) {
            Arrays.stream(names.trim().split(","))
                .forEach(name -> {
                    String dataSourceName = name;
                    if (!name.toLowerCase().contains("datasource")) {
                        dataSourceName += "DataSource";
                    }
                    dataSourceMap.put(dataSourceName, propertyResolver.getSubProperties(name + "."));
                });
        }

        if (dataSourceMap.isEmpty()) {
            LOGGER.warn("DataSource Name is Empty...");
        }
    }

    private void initPrimary() {
        primary = MapUtils.getString(commProperties, "primary");
        if (StringUtils.isEmpty(primary)) {
            primary = dataSourceMap.keySet().stream().findAny().orElse("");
        }
        if (!primary.toLowerCase().contains("datasource")) {
            primary += "DataSource";
        }
        LOGGER.warn("Primary DataSource bean name is " + primary);
    }

    private void maybeGetDriverClassName(Map<String, Object> properties) {
        if (!properties.containsKey("driverClassName") && properties.containsKey("url")) {
            String url = (String)properties.get("url");
            String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();
            properties.put("driverClassName", driverClass);
        }
    }

    private Class<? extends DataSource> findType(String typeName) {
        Class<? extends DataSource> clazz = null;
        if (StringUtils.isNotEmpty(typeName)) {
            try {
                clazz = (Class<? extends DataSource>)Class.forName(typeName);
            } catch (Exception e) {
                LOGGER.debug("can not find class: " + typeName);
            }
        }
        if (clazz == null) {
            int index = 0;
            while (index < DATA_SOURCE_TYPE_NAMES.length) {
                String name = DATA_SOURCE_TYPE_NAMES[index];
                try {
                    clazz = (Class<? extends DataSource>)Class.forName(name);
                    break;
                } catch (Exception e) {
                    LOGGER.debug("can not find class: " + name);
                    ++index;
                }
            }
        }
        if (clazz != null) {
            LOGGER.warn("dataSourceType --> " + clazz.getName());
        } else {
            LOGGER.warn("Can not find DataSource Type ", DATA_SOURCE_TYPE_NAMES);
        }

        return clazz;

    }
}

最后只需要简单的配置JdbcTemplate和DataSourceTransactionManager, 并且导入DataSourceRegister就可以使用了。

package com.mutil.transaction.config;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

/**
 * Created by WuTing on 2017/12/5.
 */
@Configuration
@Import(DataSourceRegister.class)
public class DBConfig {

    @Bean("jdbcTemplate")
    public JdbcTemplate jdbcTemplate(DynamicDataSource dataSource) {

        return new JdbcTemplate(dataSource);
    }

    @Bean("jdbcReadTemplate")
    public JdbcTemplate jdbcReadTemplate(DynamicDataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean("transactionManager")
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

启动日志:

"C:\Program Files\Java\jdk1.8.0_131\bin\java" -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:52089,suspend=y,server=n -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=52088 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:C:\Users\NCP-605\.IntelliJIdea2017.3\system\captureAgent\debugger-agent.jar=C:\Users\NCP-605\AppData\Local\Temp\capture1286.props -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;F:\code\transaction\target\classes;C:\Users\NCP-605\.m2\repository\org\springframework\boot\spring-boot-starter-web\1.5.9.RELEASE\spring-boot-starter-web-1.5.9.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\boot\spring-boot-starter\1.5.9.RELEASE\spring-boot-starter-1.5.9.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\boot\spring-boot\1.5.9.RELEASE\spring-boot-1.5.9.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\1.5.9.RELEASE\spring-boot-autoconfigure-1.5.9.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\boot\spring-boot-starter-logging\1.5.9.RELEASE\spring-boot-starter-logging-1.5.9.RELEASE.jar;C:\Users\NCP-605\.m2\repository\ch\qos\logback\logback-classic\1.1.11\logback-classic-1.1.11.jar;C:\Users\NCP-605\.m2\repository\ch\qos\logback\logback-core\1.1.11\logback-core-1.1.11.jar;C:\Users\NCP-605\.m2\repository\org\slf4j\jcl-over-slf4j\1.7.25\jcl-over-slf4j-1.7.25.jar;C:\Users\NCP-605\.m2\repository\org\slf4j\jul-to-slf4j\1.7.25\jul-to-slf4j-1.7.25.jar;C:\Users\NCP-605\.m2\repository\org\slf4j\log4j-over-slf4j\1.7.25\log4j-over-slf4j-1.7.25.jar;C:\Users\NCP-605\.m2\repository\org\yaml\snakeyaml\1.17\snakeyaml-1.17.jar;C:\Users\NCP-605\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\1.5.9.RELEASE\spring-boot-starter-tomcat-1.5.9.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\8.5.23\tomcat-embed-core-8.5.23.jar;C:\Users\NCP-605\.m2\repository\org\apache\tomcat\tomcat-annotations-api\8.5.23\tomcat-annotations-api-8.5.23.jar;C:\Users\NCP-605\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\8.5.23\tomcat-embed-el-8.5.23.jar;C:\Users\NCP-605\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\8.5.23\tomcat-embed-websocket-8.5.23.jar;C:\Users\NCP-605\.m2\repository\org\hibernate\hibernate-validator\5.3.6.Final\hibernate-validator-5.3.6.Final.jar;C:\Users\NCP-605\.m2\repository\javax\validation\validation-api\1.1.0.Final\validation-api-1.1.0.Final.jar;C:\Users\NCP-605\.m2\repository\org\jboss\logging\jboss-logging\3.3.1.Final\jboss-logging-3.3.1.Final.jar;C:\Users\NCP-605\.m2\repository\com\fasterxml\classmate\1.3.4\classmate-1.3.4.jar;C:\Users\NCP-605\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.8.10\jackson-databind-2.8.10.jar;C:\Users\NCP-605\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.8.0\jackson-annotations-2.8.0.jar;C:\Users\NCP-605\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.8.10\jackson-core-2.8.10.jar;C:\Users\NCP-605\.m2\repository\org\springframework\spring-web\4.3.13.RELEASE\spring-web-4.3.13.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\spring-context\4.3.13.RELEASE\spring-context-4.3.13.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\spring-webmvc\4.3.13.RELEASE\spring-webmvc-4.3.13.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\spring-expression\4.3.13.RELEASE\spring-expression-4.3.13.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\boot\spring-boot-starter-aop\1.5.9.RELEASE\spring-boot-starter-aop-1.5.9.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\spring-aop\4.3.13.RELEASE\spring-aop-4.3.13.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\aspectj\aspectjweaver\1.8.13\aspectjweaver-1.8.13.jar;C:\Users\NCP-605\.m2\repository\org\springframework\spring-jdbc\4.3.9.RELEASE\spring-jdbc-4.3.9.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\spring-beans\4.3.13.RELEASE\spring-beans-4.3.13.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\spring-core\4.3.13.RELEASE\spring-core-4.3.13.RELEASE.jar;C:\Users\NCP-605\.m2\repository\org\springframework\spring-tx\4.3.13.RELEASE\spring-tx-4.3.13.RELEASE.jar;C:\Users\NCP-605\.m2\repository\mysql\mysql-connector-java\6.0.6\mysql-connector-java-6.0.6.jar;C:\Users\NCP-605\.m2\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;C:\Users\NCP-605\.m2\repository\commons-dbcp\commons-dbcp\1.4\commons-dbcp-1.4.jar;C:\Users\NCP-605\.m2\repository\commons-pool\commons-pool\1.6\commons-pool-1.6.jar;C:\Users\NCP-605\.m2\repository\org\apache\velocity\velocity\1.7\velocity-1.7.jar;C:\Users\NCP-605\.m2\repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;C:\Users\NCP-605\.m2\repository\commons-lang\commons-lang\2.4\commons-lang-2.4.jar;C:\Users\NCP-605\.m2\repository\org\springframework\boot\spring-boot-starter-jta-atomikos\1.5.9.RELEASE\spring-boot-starter-jta-atomikos-1.5.9.RELEASE.jar;C:\Users\NCP-605\.m2\repository\com\atomikos\transactions-jms\3.9.3\transactions-jms-3.9.3.jar;C:\Users\NCP-605\.m2\repository\com\atomikos\transactions-jta\3.9.3\transactions-jta-3.9.3.jar;C:\Users\NCP-605\.m2\repository\com\atomikos\transactions\3.9.3\transactions-3.9.3.jar;C:\Users\NCP-605\.m2\repository\com\atomikos\transactions-api\3.9.3\transactions-api-3.9.3.jar;C:\Users\NCP-605\.m2\repository\com\atomikos\atomikos-util\3.9.3\atomikos-util-3.9.3.jar;C:\Users\NCP-605\.m2\repository\com\atomikos\transactions-jdbc\3.9.3\transactions-jdbc-3.9.3.jar;C:\Users\NCP-605\.m2\repository\javax\transaction\javax.transaction-api\1.2\javax.transaction-api-1.2.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2017.3\lib\idea_rt.jar" com.mutil.transaction.TransactionApplication
Connected to the target VM, address: '127.0.0.1:52089', transport: 'socket'

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.9.RELEASE)

2017-12-08 14:04:56.302  INFO 3124 --- [           main] c.m.transaction.TransactionApplication   : Starting TransactionApplication on CN17454-D-1 with PID 3124 (F:\code\transaction\target\classes started by NCP-605 in F:\code\transaction)
2017-12-08 14:04:56.305  INFO 3124 --- [           main] c.m.transaction.TransactionApplication   : No active profile set, falling back to default profiles: default
2017-12-08 14:04:56.344  INFO 3124 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@471a9022: startup date [Fri Dec 08 14:04:56 CST 2017]; root of context hierarchy
2017-12-08 14:04:56.503  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : Primary DataSource bean name is libraryDataSource


2017-12-08 14:04:56.739  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : libraryDataSource
2017-12-08 14:04:56.739  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : minIdle --> 1
2017-12-08 14:04:56.739  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : maxIdle --> 2
2017-12-08 14:04:56.739  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : initialSize --> 1
2017-12-08 14:04:56.739  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : driverClassName --> com.mysql.cj.jdbc.Driver
2017-12-08 14:04:56.739  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : username --> root
2017-12-08 14:04:56.739  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : password --> root
2017-12-08 14:04:56.739  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : url --> jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true
2017-12-08 14:04:56.739  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : primary --> true
2017-12-08 14:04:56.745  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : dataSourceType --> org.apache.commons.dbcp.BasicDataSource


2017-12-08 14:04:56.745  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : schemaDataSource
2017-12-08 14:04:56.745  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : minIdle --> 1
2017-12-08 14:04:56.745  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : maxIdle --> 2
2017-12-08 14:04:56.745  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : initialSize --> 1
2017-12-08 14:04:56.745  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : primary --> false
2017-12-08 14:04:56.745  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : dataSourceType --> org.apache.commons.dbcp.BasicDataSource


2017-12-08 14:04:56.746  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : sakilaDataSource
2017-12-08 14:04:56.746  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : minIdle --> 1
2017-12-08 14:04:56.746  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : maxIdle --> 2
2017-12-08 14:04:56.746  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : initialSize --> 1
2017-12-08 14:04:56.746  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : url --> jdbc:mysql://localhost:3306/sakila?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=true
2017-12-08 14:04:56.746  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : username --> root
2017-12-08 14:04:56.746  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : driverClassName --> com.mysql.cj.jdbc.Driver
2017-12-08 14:04:56.746  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : password --> root
2017-12-08 14:04:56.746  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : primary --> false
2017-12-08 14:04:56.746  WARN 3124 --- [           main] c.m.t.config.DataSourceRegister          : dataSourceType --> org.apache.commons.dbcp.BasicDataSource
2017-12-08 14:04:57.560  INFO 3124 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-12-08 14:04:57.568  INFO 3124 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2017-12-08 14:04:57.568  INFO 3124 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.23
2017-12-08 14:04:57.744  INFO 3124 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2017-12-08 14:04:57.744  INFO 3124 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1402 ms
2017-12-08 14:04:57.917  INFO 3124 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2017-12-08 14:04:57.921  INFO 3124 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-12-08 14:04:57.922  INFO 3124 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-12-08 14:04:57.922  INFO 3124 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-12-08 14:04:57.922  INFO 3124 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2017-12-08 14:04:58.357  INFO 3124 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@471a9022: startup date [Fri Dec 08 14:04:56 CST 2017]; root of context hierarchy
2017-12-08 14:04:58.409  INFO 3124 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-12-08 14:04:58.410  INFO 3124 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-12-08 14:04:58.454  INFO 3124 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-12-08 14:04:58.454  INFO 3124 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-12-08 14:04:58.489  INFO 3124 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-12-08 14:04:58.764  INFO 3124 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2017-12-08 14:04:58.809  INFO 3124 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-12-08 14:04:58.813  INFO 3124 --- [           main] c.m.transaction.TransactionApplication   : Started TransactionApplication in 2.768 seconds (JVM running for 8.779)

代码中涉及的 DynamicDataSource可在上一篇文章中找到http://blog.csdn.net/u013725455/article/details/78730515

DataSourceAspect 得内容作了小小的改变:所有的数据源名称都得包括datasource(不区分大小写)

package com.mutil.transaction.config;

import java.lang.reflect.Method;

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.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * Created by WuTing on 2017/12/5.
 */
@Component
@Aspect
@Order(1)
public class DataSourceAspect {
    private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);

    @Before(value = "execution(* com.mutil.transaction.service.*.*(..))")
    public void before(JoinPoint point) {
        DataSource annotation = this.getDataSourceAnnotation(point);
        if (annotation != null) {
            String dataSourceName = this.getDataSourceName(annotation);
            DataSourceContextHolder.setDataSourceType(dataSourceName);
            logger.debug("Set DataSource : {} > {}", dataSourceName, point.getSignature());
        }
    }

    @After(value = "execution(* com.mutil.transaction.service.*.*(..))")
    public void restoreDataSource(JoinPoint point) {

        DataSource annotation = this.getDataSourceAnnotation(point);
        if (annotation != null) {
            String dataSourceName = this.getDataSourceName(annotation);
            logger.debug("Revert DataSource : {} > {}", dataSourceName, point.getSignature());
        }
        DataSourceContextHolder.clearDataSourceType();
    }

    private String getDataSourceName(DataSource annotation) {
        String dataSourceName = annotation.value();
        if (!dataSourceName.toLowerCase().contains("datasource")){
            dataSourceName+="DataSource";
        }
        return dataSourceName;
    }

    private DataSource getDataSourceAnnotation(JoinPoint point) {
        DataSource annotation = null;
        Class[] parameterTypes = ((MethodSignature)point.getSignature()).getMethod().getParameterTypes();
        String methodName = point.getSignature().getName();
        try {
            Method method = point.getTarget().getClass().getMethod(methodName, parameterTypes);
            if (method.isAnnotationPresent(DataSource.class)) {
                annotation = method.getAnnotation(DataSource.class);
            } else {
                annotation = point.getTarget().getClass().getAnnotation(DataSource.class);
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        return annotation;
    }
}

将上一篇文章http://blog.csdn.net/u013725455/article/details/78730515中的DBConfig替换为本文的DBConfig, DataSourceAspect替换为本文的DataSourceAspect ,并且加入DataSourceRegister即可简单配置,实现跨库事务。

项目地址:https://github.com/wutingting1993/transaction

猜你喜欢

转载自blog.csdn.net/u013725455/article/details/78750780