SpringBootJDBC:加载DataSource过程的源码分析及yml中
DataSo。。。
Spring Boot实现了⾃动加载DataSource及相关配置。当然,使⽤时加上@EnableAutoConfiguration注解是必须的。下⾯就是对这⼀部分的源码分析。
(1)Spring Boot启动后会调⽤org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration。下⾯是部分源码。
1 @Configuration
2 @ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
3 @EnableConfigurationProperties(DataSourceProperties.class)
4 @Import({ DataSourcePoolMetadataProvidersConfiguration.class,
5        DataSourceInitializationConfiguration.class })
6 public class DataSourceAutoConfiguration {
7
8    @Configuration
9    @Conditional(EmbeddedDatabaseCondition.class)
10    @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
11    @Import(EmbeddedDataSourceConfiguration.class)
12    protected static class EmbeddedDatabaseConfiguration {
13    }
14
15    @Configuration
16    @Conditional(PooledDataSourceCondition.class)
17    @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
18    @Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
19            DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,
20            DataSourceJmxConfiguration.class })
21    protected static class PooledDataSourceConfiguration {
22    }
23    ......
24 }
我们从中可以看出,DataSourceAutoConfiguration中有两个嵌套类,⼀个是EmbeddedDatabaseConfiguration,另⼀个是PooledDataSourceConfiguration。
EmbeddedDatabaseConfiguration表⽰已经嵌⼊Spring Boot的DataSource,除了Maven中加⼊相应的Driver,可以不做其他额外配置就能使⽤。从EmbeddedDatabaseType类可以看出,Spring Boot的内嵌DataSource⽀持HSQL,H2,DERBY这三种DB。PooledDataSourceConfiguration表⽰Spring Boot还
⽀持⼀些实现Pool的DataSource。从org.springframework.boot.jdbc.DataSourceBuilder 中可以看出,当前版本的Spring Boot(2.0)只⽀持
com.zaxxer.hikari.HikariDataSource,at.jdbc.pool.DataSource,org.apachemons.dbcp2.BasicDataSource。其中,性能更加优秀的HikariDataSource是Spring Boot的默认选择(DataSourceBuilder中DATA_SOURCE_TYPE_NAMES[0] =
com.zaxxer.hikari.HikariDataSource)。所以,当l⽂件中做如下配置时,Spring Boot默认使⽤HikariDataSource数据库连接池。
spring:
datasource:
url: jdbc:mysql://localhost:3306/sas
username: root
password: ****
driver-class-name: sql.jdbc.Driver
#type: com.zaxxer.hikari.HikariDataSource
(2)我们以HikariDataSource举例,接下来调⽤PooledDataSourceConfiguration中
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration抽象类的Hikari嵌套类(DataSourceConfiguration抽象类的⼀个实现类)。
1 abstract class DataSourceConfiguration {
2
3    @SuppressWarnings("unchecked")
4    protected <T> T createDataSource(DataSourceProperties properties,
5            Class<? extends DataSource> type) {
6        return (T) properties.initializeDataSourceBuilder().type(type).build();
7    }
8
9    /* Omit Tomcat Pool DataSource configuration.*/
10    /**
11      * Hikari DataSource configuration.
12      */
13    @ConditionalOnClass(HikariDataSource.class)
14    @ConditionalOnProperty(name = "pe", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
15    static class Hikari extends DataSourceConfiguration {
16
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.Name())) {
23                dataSource.Name());
24            }
25            return dataSource;
26        }
27    }
28    /* Omit DBCP DataSource configuration.*/
29 }
我们从黄⾊部分可以看出,当l⽂件中配置pe = com.zaxxer.hikari.Hik
ariDataSource时,会使⽤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.
spring怎么读取propertiespassword: #Login password of the database.
## For more details please see DataSourceProperties.
hikari:
connectionTimeout:
validationTimeout:
maxPoolSize:
minIdle:
dataSourceProperties:
## For more details please see HikariConfig.
(3)当读完配置后,则会通过Connection()⽅法创建HikariPool对象。HikariPool及其⽗类PoolBase做了许多复杂的⼯作,包括创建Pool,创建Connection,读取Config,验证等等。调⽤Connection()⽅法最终得到了这个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 {
2
3    private final String jdbcUrl;
4    private final Properties driverProperties;
5    private Driver driver;
6
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 = Set().iterator();
11
12        while(e.hasNext()) {
13            Entry driverClass = (();
14            this.driverProperties.Key().toString(), Value().toString());
15        }
16
17        if(username != null) {
18            this.driverProperties.put("user", Property("user", username));
19        }
20
21        if(password != null) {
22            this.driverProperties.put("password", Property("password", password));
23        }
24    ......
25    }
26
27    @Override
28    public Connection getConnection() throws SQLException
29    {
30      t(jdbcUrl, driverProperties);
31    }
32 }
④调⽤HikariPool对象的构造器,同样也是配置⼀堆线程池信息。
⑤返回Connection()。这个过程中,做了包含wPoolEntry()及wConnection()的许多复杂⽅法。从wConnection()可以看出,最终还是调⽤的步骤③的getConnection()⽅法获取到了这个Connection对象。
1    private Connection newConnection() throws Exception
2    {
3      final long start = currentTime();
4
5      Connection connection = null;
6      try {
7          String username = Username();
8          String password = Password();
9
10          connection = (username == null) ? Connection() : Connection(username, password);
11          if (connection == null) {
12            throw new SQLTransientConnectionException("DataSource returned null unexpectedly");
13          }
14
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          }
26
27          lastConnectionFailure.set(e);
28          throw e;
29      }
30      finally {
31          // tracker will be null during failFast check
32          if (metricsTracker != null) {
33            dConnectionCreated(elapsedMillis(start));
34          }
35      }
36    }

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。