SpringBoot學習之路---數據訪問&雜談自動配置原理

SpringBoot底層與數據庫打交道是基於 SpringData來操作的,今天就來簡單記錄下這其中的奧祕


這篇博客不整合其他的ORM框架,僅僅使用jdbc的方式來探究原理。

首先我們要訪問數據庫,就需要一個數據源,有關數據源的配置SpringBoot是放在DataSourceConfiguration

我們點進去發現這個類是和全局配置文件中的spring.datasource.type屬性相綁定的:

	@ConditionalOnMissingBean({DataSource.class})
    @ConditionalOnProperty(
        name = {"spring.datasource.type"}
    )

同時,它下面有幾個方法,是依據我們系統引入了哪些包,而選用哪種數據源(SpringBoot2.x默認採用hikari數據源)

	@ConditionalOnClass({BasicDataSource.class})
    @ConditionalOnMissingBean({DataSource.class})
    @ConditionalOnProperty(
        name = {"spring.datasource.type"},
        havingValue = "org.apache.commons.dbcp2.BasicDataSource",
        matchIfMissing = true
    )
    static class Dbcp2 {
        Dbcp2() {
        }

        @Bean
        @ConfigurationProperties(
            prefix = "spring.datasource.dbcp2"
        )
        BasicDataSource dataSource(DataSourceProperties properties) {
            return (BasicDataSource)DataSourceConfiguration.createDataSource(properties, BasicDataSource.class);
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({HikariDataSource.class})
    @ConditionalOnMissingBean({DataSource.class})
    @ConditionalOnProperty(
        name = {"spring.datasource.type"},
        havingValue = "com.zaxxer.hikari.HikariDataSource",
        matchIfMissing = true
    )
    static class Hikari {
        Hikari() {
        }

        @Bean
        @ConfigurationProperties(
            prefix = "spring.datasource.hikari"
        )
        HikariDataSource dataSource(DataSourceProperties properties) {
            HikariDataSource dataSource = (HikariDataSource)DataSourceConfiguration.createDataSource(properties, HikariDataSource.class);
            if (StringUtils.hasText(properties.getName())) {
                dataSource.setPoolName(properties.getName());
            }

            return dataSource;
        }
    }

    @Configuration(
        proxyBeanMethods = false
    )
    @ConditionalOnClass({org.apache.tomcat.jdbc.pool.DataSource.class})
    @ConditionalOnMissingBean({DataSource.class})
    @ConditionalOnProperty(
        name = {"spring.datasource.type"},
        havingValue = "org.apache.tomcat.jdbc.pool.DataSource",
        matchIfMissing = true
    )
    static class Tomcat {
        Tomcat() {
        }

        @Bean
        @ConfigurationProperties(
            prefix = "spring.datasource.tomcat"
        )
        org.apache.tomcat.jdbc.pool.DataSource dataSource(DataSourceProperties properties) {
            org.apache.tomcat.jdbc.pool.DataSource dataSource = (org.apache.tomcat.jdbc.pool.DataSource)DataSourceConfiguration.createDataSource(properties, org.apache.tomcat.jdbc.pool.DataSource.class);
            DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(properties.determineUrl());
            String validationQuery = databaseDriver.getValidationQuery();
            if (validationQuery != null) {
                dataSource.setTestOnBorrow(true);
                dataSource.setValidationQuery(validationQuery);
            }

            return dataSource;
        }
    }

現在我們就去全局配置中來配置,以yaml文件爲例

spring:
  datasource:
    username: root
    password: ***
    url: jdbc:mysql://localhost:3306/demo
    driver-class-name: com.mysql.jdbc.Driver

這樣就配置好了,並且它會幫我們自動注入到容器中。有數據源後,我們就來測試一下,寫個測試方法,打印出數據源和連接:

@SpringBootTest
class SpringbootDataApplicationTests {

    @Autowired
    private DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
        System.out.println("i am datasource:"+dataSource.getClass().getName());
        Connection connection = dataSource.getConnection();
        System.out.println(connection);

    }

}

運行結果
在這裏插入圖片描述
獲取連接成功

我們目光回到DatasourceConfiguration中,如果我們想用到自己指定的數據源,它是怎麼樣的

/**
 * Generic DataSource configuration.
 */
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {

   @Bean
   public DataSource dataSource(DataSourceProperties properties) {
       //使用DataSourceBuilder創建數據源,利用反射創建響應type的數據源,並且綁定相關屬性
      return properties.initializeDataSourceBuilder().build();
   }

}

數據源這塊的源碼解析完畢,接着看看還有一個類DataSourceInitializer,它就是幫我們初始化數據源的,內部有兩個方法
runSchemaScriptsrunDataScripts,一個是幫我們運行建表語句,另外是運行插入數據庫的sql語句

  1. runSchemaScripts:它底層也是根據你指定的sql文件的路徑,去運行指定的sql腳本,如果沒有指定路徑,則默認去尋找schema.sql/schema-all.sql文件並執行。(SpringBoot2.x已經默認不掃描,有興趣的話可以查看另外一篇博客)
  2. 操作數據庫這塊,底層有一個類JdbcTemplateConfiguration,它幫我們自動注入了JdbcTemplate進容器中,我們可以直接操作
@ConditionalOnMissingBean({JdbcOperations.class})
class JdbcTemplateConfiguration {
    JdbcTemplateConfiguration() {
    }

    @Bean
    @Primary
    JdbcTemplate jdbcTemplate(DataSource dataSource, JdbcProperties properties) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        Template template = properties.getTemplate();
        jdbcTemplate.setFetchSize(template.getFetchSize());
        jdbcTemplate.setMaxRows(template.getMaxRows());
        if (template.getQueryTimeout() != null) {
            jdbcTemplate.setQueryTimeout((int)template.getQueryTimeout().getSeconds());
        }

        return jdbcTemplate;
    }
}

到這裏咱們就可以在測試類直接注入jdbcTemplate來進行操作了,這裏就略過了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章