SpringBoot配置多数据源
工具: spring tool suite
整体架构为:
- 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.hrf</groupId>
<artifactId>springboot_2-1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-5-2</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.15.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>
</properties>
<dependencies>
<!--Spring data JPA依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(2)
application.properties
# 主数据源
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdb
spring.datasource.username=root
spring.datasource.password=
custom.datasource.names=ds1,ds2
custom.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds1.url=jdbc:mysql://localhost:3306/springbootdb
custom.datasource.ds1.username=root
custom.datasource.ds1.password=
custom.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds2.url=jdbc:mysql://localhost:3306/springbootdb
custom.datasource.ds2.username=root
custom.datasource.ds2.password=
(3)
Multipart.java
package com.hrf;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.sql.DataSource;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.AnnotationScopeMetadataResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ScopeMetadata;
import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.core.env.Environment;
/**
*
* 动态创建多数据源注册到Spring中 接口:BeanDefinitionRegistryPostProcessor主要是注入bean
*
* 接口:接口 EnvironmentAware 重写方法 setEnvironment
* 可以在工程启动时,获取到系统环境变量和application配置文件中的变量。
*
* 方法的执行顺序是: setEnvironment()-->postProcessBeanDefinitionRegistry() -->
* postProcessBeanFactory()
*
* @author Administrator
*
*/
@Configuration
public class Multipart
implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {
// 作用域对象.
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
// bean名称生成器.
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
// 如配置文件中未指定数据源类型,使用该默认值
private static final Object DATASOURCE_TYPE_DEFAULT = "org.apache.tomcat.jdbc.pool.DataSource";
// 存放DataSource配置的集合;
private Map<String, Map<String, Object>> dataSourceMap = new HashMap<String, Map<String, Object>>();
@Override
public void setEnvironment(Environment environment) {
System.out.println("MultipleDataSourceBeanDefinitionRegistryPostProcessor.setEnvironment()");
/*
* 获取application.properties配置的多数据源配置,添加到map中,
* 之后在postProcessBeanDefinitionRegistry进行注册。
*/
// 获取到前缀是"custom.datasource." 的属性列表值.
RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(environment, "custom.datasource.");
// 获取到所有数据源的名称.
String dsPrefixs = propertyResolver.getProperty("names");
String[] dsPrefixsArr = dsPrefixs.split(",");
for (String dsPrefix : dsPrefixsArr) {
/*
* 获取到子属性,对应一个map; 也就是这个map的key就是
*
* type、driver-class-name等;
*
*/
Map<String, Object> dsMap = propertyResolver.getSubProperties(dsPrefix + ".");
// 存放到一个map集合中,之后在注入进行使用.
dataSourceMap.put(dsPrefix, dsMap);
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 设置为主数据源;
beanFactory.getBeanDefinition("dataSource").setPrimary(true);
if (!dataSourceMap.isEmpty()) {
// 不为空的时候.
BeanDefinition bd = null;
Map<String, Object> dsMap = null;
MutablePropertyValues mpv = null;
for (Entry<String, Map<String, Object>> entry : dataSourceMap.entrySet()) {
bd = beanFactory.getBeanDefinition(entry.getKey());
mpv = bd.getPropertyValues();
dsMap = entry.getValue();
mpv.addPropertyValue("driverClassName", dsMap.get("driverClassName"));
mpv.addPropertyValue("url", dsMap.get("url"));
mpv.addPropertyValue("username", dsMap.get("username"));
mpv.addPropertyValue("password", dsMap.get("password"));
}
}
}
@SuppressWarnings("unchecked")
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("MultipleDataSourceBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()");
try {
if (!dataSourceMap.isEmpty()) {
// 不为空的时候,进行注册bean.
for (Entry<String, Map<String, Object>> entry : dataSourceMap.entrySet()) {
Object type = entry.getValue().get("type");// 获取数据源类型,没有设置为默认的数据源.
if (type == null) {
type = DATASOURCE_TYPE_DEFAULT;
}
registerBean(registry, entry.getKey(),
(Class<? extends DataSource>) Class.forName(type.toString()));
}
}
} catch (ClassNotFoundException e) {
// 异常捕捉.
e.printStackTrace();
}
}
/**
* 注册Bean到Spring
*
* @param registry
* @param name
* @param beanClass
*/
private void registerBean(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
// 单例还是原型等等...作用域对象.
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 可以自动生成name
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
}
(4)
TestController.java
package com.hrf;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
// 没有指定为主数据源.
@Autowired
private DataSource dataSource;
@Autowired
@Qualifier("ds1")
private DataSource dataSource1;
@Autowired
@Qualifier("ds2")
private DataSource dataSource2;
private JdbcTemplate jdbcTemplate;
@Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
System.out.println("TestController.setJdbcTemplate()");
jdbcTemplate.setDataSource(dataSource1);// 设置dataSource
this.jdbcTemplate = jdbcTemplate;
}
@RequestMapping("/get")
public String get() {
// 观察控制台的打印信息.
System.out.println(dataSource);
return "ok";
}
@RequestMapping("/get1")
public String get1() {
// 观察控制台的打印信息.
System.out.println(dataSource1);
return "ok.1";
}
@RequestMapping("/get2")
public String get2() {
// 观察控制台的打印信息.
System.out.println(dataSource2);
return "ok.2";
}
@RequestMapping("/get3")
public String get3() {
// 观察控制台的打印信息.
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource1);
System.out.println(jdbcTemplate.getDataSource());
System.out.println(jdbcTemplate);
/*
* Demo1只在test1中存在,test并没有此数据库; 需要自己自己进行复制,不然会报错:Table 'test1.demo1'
* doesn't exist
*/
String sql = "select * from user_info";
jdbcTemplate.query(sql, new RowMapper<String>() {
@Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
System.out.println(rs.getLong("uid") + "---" + rs.getString("name"));
return "";
}
});
return "ok.3";
}
@RequestMapping("/get4")
public String get4() {
// 观察控制台的打印信息.
System.out.println(jdbcTemplate.getDataSource());
System.out.println(jdbcTemplate);
/*
* Demo1只在test1中存在,test并没有此数据库; 需要自己自己进行复制,不然会报错:Table 'test1.demo1'
* doesn't exist
*/
String sql = "select *from user_info";
jdbcTemplate.query(sql, new RowMapper<String>() {
@Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
System.out.println(rs.getLong("uid") + "---" + rs.getString("name"));
return "";
}
});
return "ok.4";
}
}
(5)
SpringBoot52Application.java
package com.hrf;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBoot52Application {
public static void main(String[] args) {
SpringApplication.run(SpringBoot52Application.class, args);
}
}
让我们来体验一把:
找到SpringBoot52Application.java文件 ——》右击Run As JavaApplication——》浏览器访问: http://localhost:8080/get
结果为:ok
欢迎关注博客: