DataSourceConfiguration {
17 @Bean
18 @ConfigurationProperties(prefix = "spring.datasource.hikari")
19 public HikariDataSource dataSource(DataSourceProperties properties) {
20 HikariDataSource dataSource = createDataSource(properties,
21 HikariDataSource.class);
22 if (StringUtils.hasText(properties.getName())) {
23 dataSource.setPoolName(properties.getName());
24 }
25 return dataSource;
26 }
27 }
28 /* Omit DBCP DataSource configuration.*/
我们从黄色部分可以看出,当application.yml文件中配置spring.datasource.type = com.zaxxer.hikari.HikariDataSource时,会使用HikariDataSource作为数据库连接池(当然上面也分析了,它是默认选择)。我们从绿色部分可以看出它的配置信息主要从两个类中读取,一个是org.springframework.boot.autoconfigure.jdbc.DataSourceProperties,另一个则是本类HikariDataSource的父类com.zaxxer.hikari.HikariConfig。
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties implements BeanClassLoaderAware, InitializingBean {}
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariDataSource dataSource(DataSourceProperties properties) {}
我们从@ConfigurationProperties配置及两个具体的类所包含的的域可以得出配置HikariDataSource信息。下面是例子。
spring:
datasource:
name: #Name of the datasource. Default to "testdb" when using an embedded database.
driverClassName: #Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.
url: #DBC URL of the database.
type: #Fully qualified name of the connection pool implementation to use. By default, it is auto-detected from the classpath.
username: #Login username of the database.
password: #Login password of the database.
## For more details please see DataSourceProperties.
hikari:
connectionTimeout:
validationTimeout:
maxPoolSize:
minIdle:
dataSourceProperties:
## For more details please see HikariConfig.
(3)当读完配置后,则会通过HikariDataSource.getConnection()方法创建HikariPool对象。HikariPool及其父类PoolBase做了许多复杂的工作,包括创建Pool,创建Connection,读取Config,验证等等。调用HikariDataSource.getConnection()方法最终得到了这个Connection对象。这个过程中主要做了以下几步:
① 创建HikariPool对象。
② 调用HikariPool对象的父类对象PoolBase的构造器,读取HikariConfig配置信息配置PoolBase的属性。
③ 调用PoolBase的构造器的initializeDataSource方法,利用com.zaxxer.hikari.util.DriverDataSource创建DataSource对象(这里主要指JDBC URL方式)。DriverDataSource中会把所有的DataSource信息封装到driverProperties属性中,这是为了适配java.sql.Driver的connect(String url, java.util.Properties info)方法。
1 public final class DriverDataSource implements DataSource {
3 private final String jdbcUrl;
4 private final Properties driverProperties;
5 private Driver driver;
7 public DriverDataSource(String jdbcUrl, String driverClassName, Properties properties, String username, String password) {
8 this.jdbcUrl = jdbcUrl;
9 this.driverProperties = new Properties();
10 Iterator e = properties.entrySet().iterator();
12 while(e.hasNext()) {
13 Entry driverClass = (Entry)e.next();
14 this.driverProperties.setProperty(driverClass.getKey().toString(), driverClass.getValue().toString());
15 }
17 if(username != null) {
18 this.driverProperties.put("user", this.driverProperties.getProperty("user", username));
19 }
21 if(password != null) {
22 this.driverProperties.put("password", this.driverProperties.getProperty("password", password));
23 }
24 ......
25 }
27 @Override
28 public Connection getConnection() throws SQLException
29 {
30 return driver.connect(jdbcUrl, driverProperties);
31 }
④ 调用HikariPool对象的构造器,同样也是配置一堆线程池信息。
⑤ 返回HikariPool.getConnection()。这个过程中,做了包含PoolBase.newPoolEntry()及PoolBase.newConnection()的许多复杂方法。从PoolBase.newConnection()可以看出,最终还是调用的步骤③的getConnection()方法获取到了这个Connection对象。
1 private Connection newConnection() throws Exception
3 final long start = currentTime();
5 Connection connection = null;
6 try {
7 String username = config.getUsername();
8 String password = config.getPassword();
10 connection = (username == null) ? dataSource.getConnection() : dataSource.getConnection(username, password);
11 if (connection == null) {
12 throw new SQLTransientConnectionException("DataSource returned null unexpectedly");
13 }
15 setupConnection(connection);
16 lastConnectionFailure.set(null);
17 return connection;
18 }
19 catch (Exception e) {
20 if (connection != null) {
21 quietlyCloseConnection(connection, "(Failed to create/setup connection)");
22 }
23 else if (getLastConnectionFailure() == null) {
24 LOGGER.debug("{} - Failed to create/setup connection: {}", poolName, e.getMessage());
25 }
27 lastConnectionFailure.set(e);
28 throw e;
29 }
30 finally {
31 // tracker will be null during failFast check
32 if (metricsTracker != null) {
33 metricsTracker.recordConnectionCreated(elapsedMillis(start));
34 }
35 }