SpringBoot学习之路---数据访问&杂谈自动配置原理
程序员文章站
2022-04-19 21:59:58
...
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
,它就是帮我们初始化数据源的,内部有两个方法runSchemaScripts
和runDataScripts
,一个是帮我们运行建表语句,另外是运行插入数据库的sql语句
-
runSchemaScripts
:它底层也是根据你指定的sql文件的路径,去运行指定的sql脚本,如果没有指定路径,则默认去寻找schema.sql/schema-all.sql
文件并执行。(SpringBoot2.x已经默认不扫描,有兴趣的话可以查看另外一篇博客) - 操作数据库这块,底层有一个类
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
来进行操作了,这里就略过了