注意標題:這裏是定義多個默認類型的數據源,不是引用了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便可。