博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
springboot2.0下为JPA定义多个默认数据源
阅读量:7055 次
发布时间:2019-06-28

本文共 8813 字,大约阅读时间需要 29 分钟。

hot3.png

 

注意标题:这里是定义多个默认类型的数据源,不是引用了druid等其他的DataSource

环境:

这里直接贴pom文件的内容:

引入的springboot为:

org.springframework.boot
spring-boot-starter-parent
2.1.2.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-aop
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-devtools
runtime
org.springframework.boot
spring-boot-starter-test
test
mysql
mysql-connector-java
org.projectlombok
lombok
1.18.4

这里使用的是springboot的版本是2.1.2.RELEASE,这里特意标注出版本,是想说版本不同代码肯定会有差异,配置也会随之不同。(至少我们在开发过程中的代码、文档也会有版本管理吧)

在springboot中,默认的dataSource根本不需要开发人员再单独写代码配置,只需要在application.properties文件中添加以下内容即可:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/shirodemo?useUnicode=true&characterEncoding=utf8spring.datasource.username=rootspring.datasource.password=123456

配置完成,启动springboot就可以使用这个数据源了。

在我们做项目过程中,单一数据源开始不能满足我们的需要了,需要配置多个数据源,那么该怎么操作呢?

首先,还是需要在application.properties文件中书写相关配置,与默认的配置略有差异,比如我这里配置的两个数据源:

spring.datasource.secondary.driverClassName=com.mysql.cj.jdbc.Driverspring.datasource.secondary.jdbcUrl=jdbc:mysql://localhost:3306/shirodemo?useUnicode=true&characterEncoding=utf8spring.datasource.secondary.username=rootspring.datasource.secondary.password=123456spring.datasource.primary.jdbcUrl=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8spring.datasource.primary.username=rootspring.datasource.primary.password=123456spring.datasource.primary.driverClassName=com.mysql.cj.jdbc.Driver

说明:

数据源的配置还是写在spring.datasource前缀之后,不同的数据源使用用于区别的名称,例如:primary、secondary等等,在名称后面再追加驱动类名、用户名、密码、url等内容。需要注意的是这里的驱动类名与默认的情况不同,默认采用的是driver-class-name,而这里使用的是driverClassName。另外url参数名也有变化,由原来的url变成了jdbcUrl(为啥不同稍后介绍)

配置完成了,那么接下来就开始编写自定义配置类(springboot是代码配置咯),先贴代码,然后解释:

import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.boot.jdbc.DataSourceBuilder;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;@Configurationpublic class DataSourceConfig {    @Bean(name = "primaryDataSource")    @Qualifier("primaryDataSource")    @ConfigurationProperties(prefix = "spring.datasource.primary")    public DataSource primaryDataSource(){        return DataSourceBuilder.create().build();    }    @Bean(name = "secondaryDataSource")    @Qualifier("secondaryDataSource")    @ConfigurationProperties(prefix = "spring.datasource.secondary")    public DataSource secondaryDataSource(){        return DataSourceBuilder.create().build();    }}

接触过springboot的基本都可以看懂这个代码,需要注意的是@ConfigurationProperties这个注解,标明了前缀。另外一个需要看的就是定义的两个数据源,使用的代码却是一样的:

DataSourceBuilder.create().build();

结果会是一样吗?答案是不同的两个数据源。

分析一下DataSourceBuilder源码,DataSourceBuilder.create()的源码如下

public static DataSourceBuilder
create() { return new DataSourceBuilder<>(null); } public static DataSourceBuilder
create(ClassLoader classLoader) { return new DataSourceBuilder<>(classLoader); } private DataSourceBuilder(ClassLoader classLoader) { this.classLoader = classLoader; }

这里没什么特别的地方,是告诉DataSourceBuilder使用的classLoader而已。

build方法内容如下:

@SuppressWarnings("unchecked")	public T build() {		Class
type = getType(); DataSource result = BeanUtils.instantiateClass(type); maybeGetDriverClassName(); bind(result); return (T) result; }

第一行是获取DataSource实际类型,getType源码

private Class
getType() { Class
type = (this.type != null) ? this.type : findType(this.classLoader); if (type != null) { return type; } throw new IllegalStateException("No supported DataSource type found"); }

如果未制定,则调用findType方法:

private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] {			"com.zaxxer.hikari.HikariDataSource",			"org.apache.tomcat.jdbc.pool.DataSource",			"org.apache.commons.dbcp2.BasicDataSource" };。。。。。	@SuppressWarnings("unchecked")	public static Class
findType(ClassLoader classLoader) { for (String name : DATA_SOURCE_TYPE_NAMES) { try { return (Class
) ClassUtils.forName(name, classLoader); } catch (Exception ex) { // Swallow and continue } } return null; }

从上面的代码中,我们可以看出默认寻找的是三个指定的Datasource类型,所以默认情况下如果存在第一个,那么返回的就是com.zaxxer.hikari.HikariDataSource类型,事实上Debug信息显示的确实如此:

回到build方法中,第二行就是创建DataSource实例,不去深入。第三行maybeGetDriverClassName(),根据字面意思就是获取驱动类名称:

private void maybeGetDriverClassName() {		if (!this.properties.containsKey("driverClassName")				&& this.properties.containsKey("url")) {			String url = this.properties.get("url");			String driverClass = DatabaseDriver.fromJdbcUrl(url).getDriverClassName();			this.properties.put("driverClassName", driverClass);		}	}	private void bind(DataSource result) {		ConfigurationPropertySource source = new MapConfigurationPropertySource(				this.properties);		ConfigurationPropertyNameAliases aliases = new ConfigurationPropertyNameAliases();		aliases.addAliases("url", "jdbc-url");		aliases.addAliases("username", "user");		Binder binder = new Binder(source.withAliases(aliases));		binder.bind(ConfigurationPropertyName.EMPTY, Bindable.ofInstance(result));	}

这个方法的第一行代码就告诉我们,需要指定的属性是driverClassName。如果没有这个属性,则会跳转到bind方法进行属性绑定。如果这里还没绑定成功,spring容器会去绑定。

这里解释一下为啥使用driverClassName。这是因为使用的数据源是HikariDataSource,而这个数据源的属性就是driverClassName,所以。。。不解释了。简单贴一下HikariDataSource的源码:

public class HikariDataSource extends HikariConfig implements DataSource, Closeable{   private static final Logger LOGGER = LoggerFactory.getLogger(HikariDataSource.class);   private final AtomicBoolean isShutdown = new AtomicBoolean();}//类继承了HikariConfigpublic class HikariConfig implements HikariConfigMXBean{   private static final Logger LOGGER = LoggerFactory.getLogger(HikariConfig.class);   private static final char[] ID_CHARACTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();   private static final long CONNECTION_TIMEOUT = SECONDS.toMillis(30);   private static final long VALIDATION_TIMEOUT = SECONDS.toMillis(5);   private static final long IDLE_TIMEOUT = MINUTES.toMillis(10);   private static final long MAX_LIFETIME = MINUTES.toMillis(30);   private static final int DEFAULT_POOL_SIZE = 10;   private static boolean unitTest = false;   // Properties changeable at runtime through the HikariConfigMXBean   //   private volatile String catalog;   private volatile long connectionTimeout;   private volatile long validationTimeout;   private volatile long idleTimeout;   private volatile long leakDetectionThreshold;   private volatile long maxLifetime;   private volatile int maxPoolSize;   private volatile int minIdle;   private volatile String username;   private volatile String password;   // Properties NOT changeable at runtime   //   private long initializationFailTimeout;   private String connectionInitSql;   private String connectionTestQuery;   private String dataSourceClassName;   private String dataSourceJndiName;   private String driverClassName;   private String jdbcUrl;   private String poolName;   private String schema;   private String transactionIsolationName;   private boolean isAutoCommit;   private boolean isReadOnly;   private boolean isIsolateInternalQueries;   private boolean isRegisterMbeans;   private boolean isAllowPoolSuspension;   private DataSource dataSource;   private Properties dataSourceProperties;   private ThreadFactory threadFactory;   private ScheduledExecutorService scheduledExecutor;   private MetricsTrackerFactory metricsTrackerFactory;   private Object metricRegistry;   private Object healthCheckRegistry;   private Properties healthCheckProperties;....}

看到了吧?这里有driverClassName

 

补充一下:为了使用自定义数据源,需要将默认数据源自动配置排除在外,具体方法:

@SpringBootApplication(exclude = {        DataSourceAutoConfiguration.class})@EnableTransactionManagementpublic class ShirodemoApplication {    public static void main(String[] args) {        SpringApplication.run(ShirodemoApplication.class, args);    }}

在SpringBootApplication注解中添加exclude,指定DataSourceAutoConfiguration.class即可。

转载于:https://my.oschina.net/OHC1U9jZt/blog/3010328

你可能感兴趣的文章
split、replace、indexof、substr 用法 (获取后台富文本框内容,截取图片)
查看>>
怎样在 ubuntu 上安装 Linux 3.11 内核
查看>>
struts2配置
查看>>
bzoj 1067: [SCOI2007]降雨量
查看>>
我的友情链接
查看>>
ArcGIS 基础1-打开地图文档并浏览
查看>>
我的友情链接
查看>>
php 字符串分割函数split
查看>>
Bex5自动编号相关函数和用法
查看>>
机柜就是数据中心
查看>>
详解NetAppFAS3220数据恢复操作方法
查看>>
容器与依赖注入
查看>>
老男孩Linux运维决心书
查看>>
VIM常用快捷键
查看>>
网络交换机对无线网络中安全威胁的防御和缓解
查看>>
我的友情链接
查看>>
版权之争,谁更棋高一着?
查看>>
通过Nginx架设灵活的网站静态化方案
查看>>
php扩展模块作用及中文注释
查看>>
win7系统备份与恢复、两台虚拟机互联
查看>>