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> dataSourceMap = new HashMap<>();
private static Map commProperties = new HashMap<>();
private static Map 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 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> 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