注意标题:这里是定义多个默认类型的数据源,不是引用了druid等其余的DataSourcejava
环境:mysql
这里直接贴pom文件的内容:web
引入的springboot为:spring
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--mysql-connector--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.4</version> </dependency>
这里使用的是springboot的版本是2.1.2.RELEASE,这里特地标注出版本,是想说版本不一样代码确定会有差别,配置也会随之不一样。(至少咱们在开发过程当中的代码、文档也会有版本管理吧)sql
在springboot中,默认的dataSource根本不须要开发人员再单独写代码配置,只须要在application.properties文件中添加如下内容便可:apache
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/shirodemo?useUnicode=true&characterEncoding=utf8 spring.datasource.username=root spring.datasource.password=123456
配置完成,启动springboot就可使用这个数据源了。tomcat
在咱们作项目过程当中,单一数据源开始不能知足咱们的须要了,须要配置多个数据源,那么该怎么操做呢?springboot
首先,仍是须要在application.properties文件中书写相关配置,与默认的配置略有差别,好比我这里配置的两个数据源:app
spring.datasource.secondary.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.secondary.jdbcUrl=jdbc:mysql://localhost:3306/shirodemo?useUnicode=true&characterEncoding=utf8 spring.datasource.secondary.username=root spring.datasource.secondary.password=123456 spring.datasource.primary.jdbcUrl=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 spring.datasource.primary.username=root spring.datasource.primary.password=123456 spring.datasource.primary.driverClassName=com.mysql.cj.jdbc.Driver
说明:spring-boot
数据源的配置仍是写在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; @Configuration public 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<? extends DataSource> type = getType(); DataSource result = BeanUtils.instantiateClass(type); maybeGetDriverClassName(); bind(result); return (T) result; }
第一行是获取DataSource实际类型,getType源码
private Class<? extends DataSource> getType() { Class<? extends DataSource> 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<? extends DataSource> findType(ClassLoader classLoader) { for (String name : DATA_SOURCE_TYPE_NAMES) { try { return (Class<? extends DataSource>) 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(); } //类继承了HikariConfig public 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 }) @EnableTransactionManagement public class ShirodemoApplication { public static void main(String[] args) { SpringApplication.run(ShirodemoApplication.class, args); } }
在SpringBootApplication注解中添加exclude,指定DataSourceAutoConfiguration.class便可。