博观而约取,厚积而薄发。这篇文章主要讲述SpringBoot | 3.1 配置数据源及JDBC #yyds干货盘点#相关的知识,希望能为你提供帮助。
【SpringBoot | 3.1 配置数据源及JDBC #yyds干货盘点#】@TOC
前言前面介绍了SpringBoot的自动配置原理,用一句话概括是:启动时加载所有,最终按照条件进行装配。本章节表面上是讲数据访问,但其核心还是讲SpringBoot的自动配置,只不过自动配置的对象是数据库相关的依赖(如:druid、MyBatis、MyBatis-Plugs等)。这些依赖的导入与装配都是SpringBoot帮我们自动完成的。
SpringBoot默认使用的数据源是Hikari
(下面有源码分析),以后我们将使用阿里的Druid
数据源进行数据库相关配置与操作。
在本篇,我们可以知道:
- 数据源的自动配置原理(2.);
- SpringBoot整合第三方技术的两种方式(3.);
- SpringBoot在处理自动配置时的逻辑(3.2.2);
- Druid数据源自动配置原理(3.2.2);
1. 数据源的自动配置首先导入JDBC场景依赖
<
dependency>
<
groupId>
org.springframework.boot<
/groupId>
<
artifactId>
spring-boot-starter-data-jdbc<
/artifactId>
<
/dependency>
导入JDBC场景依赖后,我们可以在Maven的Dependencies依赖里看出
spring-boot-starter-data-jdbc
自动帮我们引入了数据源、JDBC与事务相关jar包。文章图片
少了数据库连接驱动依赖
我们可以发现,这其中没有数据库连接驱动依赖,道理很简单,SpringBoot并不知道我们要使用什么数据库(mysql还是Oracle或其他)。
直接在pom.xml文件里添加数据库驱动依赖即可
<
dependency>
<
groupId>
mysql<
/groupId>
<
artifactId>
mysql-connector-java<
/artifactId>
<
/dependency>
我们不用关注数据库驱动的版本,在SpringBoot里使用版本仲裁自动匹配( 数据库版本和驱动版本对应 ),当然,我们也可以自定义版本。
自定义连接驱动版本:
pom.xml
里dependency
直接依赖引入具体版本(maven的就近依赖原则)
< dependency> < groupId> mysql< /groupId> < artifactId> mysql-connector-java< /artifactId> < version> 5.1.49< /version> < /dependency>
pom.xml
里properties
重新声明版本(maven属性的就近优先原则)
< properties> < java.version> 1.8< /java.version> < mysql.version> 5.1.49< /mysql.version> < /properties>
文章图片
往下翻翻找到jdbc的包:
文章图片
可以看到引入jdbc相关依赖后SpringBoot帮我们引入了很多自动配置类,如:
DataSourceAutoConfiguration
:数据源的自动配置类;
DataSourceTransactionManagerAutoConfiguration
:事务管理器的自动配置;
JdbcTemplateAutoConfiguration
:JdbcTemplate的自动配置,可以来对数据库进行crud(JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用);
JndiDataSourceAutoConfiguration
:jndi的自动配置;
XADataSourceAutoConfiguration
:分布式事务相关的自动配置;
- 等......
2.1 DataSourceAutoConfiguration:数据源自动配置类其中
DataSourceAutoConfiguration
是数据源的自动配置类,我们点进去看源码,发现其定义了一些静态方法,其中底层数据源相关的是:@Configuration(proxyBeanMethods = false)
@Conditional(DataSourceAutoConfiguration.PooledDataSourceCondition.class)
@ConditionalOnMissingBean(DataSource.class, XADataSource.class)
@Import(Hikari.class, Tomcat.class, Dbcp2.class, OracleUcp.class, Generic.class, DataSourceJmxConfiguration.class)
protected static class PooledDataSourceConfiguration
protected PooledDataSourceConfiguration()
其中老熟人
@ConditionalOnMissingBean
注解的含义是当容器内没有DataSource数据源时,才进行下面的自动配置默认的数据源;而@Import
注解则说明了我们要引入的默认数据源是Hikari数据源。也就是说,在我们不做任何处理的情况下,SpringBoot为我们底层配置好的连接池是:HikariDataSource
。2.2 JdbcTemplateAutoConfiguration:JdbcTemplate的自动配置类JdbcTemplateAutoConfiguration源码:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(DataSource.class, JdbcTemplate.class)
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
@Import(JdbcTemplateConfiguration.class, NamedParameterJdbcTemplateConfiguration.class)
public class JdbcTemplateAutoConfiguration
public JdbcTemplateAutoConfiguration()
从
@EnableConfigurationProperties
注解可知,自动配置的相关属性在JdbcProperties.class
类里,我们点进去看看:文章图片
通过源码我们可以知道以下信息:
- 可以在application.properties文件里修改jdbc相关属性,前缀是:
spring.jdbc
- 可配置项有:
- fetchSize:为jdbc驱动程序提供一个提示,它提示此Statement生成的ResultSet对象需要更多行时应该从数据库获取的行数。
- maxRows:将此Statement 对象生成的所有ResultSet对象可以包含的最大行数限制设置为给定数。
- queryTimeout:超时设置。
- 等……
文章图片
2.3 修改数据源的配置项这里直接给出示例:
spring:
datasource:
url: jdbc:mysql://localhost:3306/db_account
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver#默认配置,可不写
#type: com.zaxxer.hikariDataSource
测试类如下:
@Slf4j
@SpringBootTest
class Boot05WebAdminApplicationTests @Autowired
JdbcTemplate jdbcTemplate;
@Test
void contextLoads() //jdbcTemplate.queryForObject("select * from account_tbl")
//jdbcTemplate.queryForList("select * from account_tbl",)
Long aLong = jdbcTemplate.queryForObject("select count(*) from account_tbl", Long.class);
log.info("记录总数:",aLong);
3. 配置Druid数据源的两种方式Druid官方github地址为:https://github.com/alibaba/druid
在SpringBoot中,整合第三方技术有两种方式:自定义与starter。在实际生产中一般使用starter,它只需要引入一个xxx-spring-boot-starter依赖就好,能帮我们省去很多配置工作。但我们也可能遇到自定义配置的需求,因此这两种方法都会提及。
3.1 自定义配置Druid数据源1) 首先引入druid数据源依赖
<
dependency>
<
groupId>
com.alibaba<
/groupId>
<
artifactId>
druid<
/artifactId>
<
version>
1.1.17<
/version>
<
/dependency>
2) SpringBoot采用编写配置类的方式
@Configuration
public class MyDataSourceConfig // 默认的自动配置是判断容器中没有才会配@ConditionalOnMissingBean(DataSource.class),即有@Bean后容器自动配置不生效
@ConfigurationProperties("spring.datasource") //绑定属性
@Bean
public DataSource dataSource() throws SQLException
DruidDataSource druidDataSource = new DruidDataSource();
//在注册自己的数据源时要给核心属性赋值,又因为不能写死在代码里,故抽取到配置文件里
//druidDataSource.setUrl();
//druidDataSource.setUsername();
//druidDataSource.setPassword();
//加入监控功能(可写进配置文件)
druidDataSource.setFilters("stat,wall");
//设置最大活跃线程数(可写进配置文件)
druidDataSource.setMaxActive(10);
return druidDataSource;
/**
* 配置 druid的监控页功能
* @return
*/
@Bean
public ServletRegistrationBean statViewServlet()
StatViewServlet statViewServlet = new StatViewServlet();
ServletRegistrationBean<
StatViewServlet>
registrationBean = new ServletRegistrationBean<
>
(statViewServlet, "/druid/*");
//配置初始化参数:需要账号密码才能登陆查看监控页面
registrationBean.addInitParameter("loginUsername","admin");
registrationBean.addInitParameter("loginPassword","123456");
return registrationBean;
/**
* WebStatFilter 用于采集web-jdbc关联监控的数据
*/
@Bean
public FilterRegistrationBean webStatFilter()
WebStatFilter webStatFilter = new WebStatFilter();
FilterRegistrationBean<
WebStatFilter>
filterRegistrationBean = new FilterRegistrationBean<
>
(webStatFilter);
//设置拦截路径
filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
优化写法:凡是setxxx方法都可以在配置文件中说明,优化后可在配置文件中直接说明。Spring原生配置方式:
<
bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close">
<
property name="url" value="https://www.songbingjia.com/android/$jdbc.url" />
<
property name="username" value="https://www.songbingjia.com/android/$jdbc.username" />
<
property name="password" value="https://www.songbingjia.com/android/$jdbc.password" />
<
property name="maxActive" value="https://www.songbingjia.com/android/20" />
<
property name="initialSize" value="https://www.songbingjia.com/android/1" />
<
property name="maxWait" value="https://www.songbingjia.com/android/60000" />
<
property name="minIdle" value="https://www.songbingjia.com/android/1" />
<
property name="timeBetweenEvictionRunsMillis" value="https://www.songbingjia.com/android/60000" />
<
property name="minEvictableIdleTimeMillis" value="https://www.songbingjia.com/android/300000" />
<
property name="testWhileIdle" value="https://www.songbingjia.com/android/true" />
<
property name="testOnBorrow" value="https://www.songbingjia.com/android/false" />
<
property name="testOnReturn" value="https://www.songbingjia.com/android/false" />
<
property name="poolPreparedStatements" value="https://www.songbingjia.com/android/true" />
<
property name="maxOpenPreparedStatements" value="https://www.songbingjia.com/android/20" />
3.2 自动配置Druid数据源及源码分析在实际生产中,我们大部分时候使用自动配置方式;相比上面繁琐而复杂的工作,自动配置就简单很多了,这里先列出相关步骤方法在,再做源码分析,看看SpringBoot为我们干了些什么。
3.2.1 自动配置Druid数据源
1) 引入druid-starter
<
dependency>
<
groupId>
com.alibaba<
/groupId>
<
artifactId>
druid-spring-boot-starter<
/artifactId>
<
version>
1.1.17<
/version>
<
/dependency>
*小知识:第三方提供的Starter统一用xxx-spring-boot-starter;而官方提供的Starter统一用spring-boot-starter-xxx。
2) 直接配置即可
spring:
datasource:#数据源的基本属性
url: jdbc:mysql://localhost:3306/db_account
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driverdruid:#druid数据源相关配置
aop-patterns: com.atguigu.admin.*#监控SpringBean
filters: stat,wall# 底层开启功能,stat(sql监控),wall(防火墙)stat-view-servlet:# 配置监控页功能
enabled: true#默认false,需要手动开启
login-username: admin#登录的用户名
login-password: admin#登录的密码
resetEnable: false#禁用重置按钮web-stat-filter:# 监控web
enabled: true
urlPattern: /*#匹配的路径
exclusions: *.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*#排除的路径filter:
stat:# 对上面filters里面的stat的详细配置
enabled: true
slow-sql-millis: 1000#慢查询时间,超过1000ms的查询都是慢查询
logSlowSql: true#是否使用日志记录慢查询
wall:# 对上面filters里面的wall的详细配置
enabled: true
config:
drop-table-allow: false
SpringBoot配置官方示例:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
配置项列表:
https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE%E5%B1%9E%E6%80%A7%E5%88%97%E8%A1%A8
3.2.2 *自动配置的源码分析
【核心原理】原理概述:
- 导入starter场景启动器后,根据SpringBoot的设置模式,首先找到
META-INF
包下的spring.factories
工厂,通过读取EnableAutoConfiguration
获取启动时加载的类 :XXXAutoConfiguration
自动配置类; - 自动配置类会利用
@Bean
注解把场景下相关组件注册进容器中,这些组件的核心配置项会通过@EnableConfigurationProperties
注解跟XXXProperties
配置文件绑定;
- 由此我们可以获得配置类(XXXAutoConfiguration)与配置项(XXXProperties)信息。
- 配置类(XXXAutoConfiguration)里配置了核心组件;
- 配置项(XXXProperties)里主要包含两个信息。其一是通过
@ConfigurationProperties
注解可以获取配置文件的前缀(prefix=Constants.XXX);其二是配置项可修改的参数(YYY)名称及参数(ZZZ)。我们在yml里通过[前缀.参数名称=参数](XXX.YYY=ZZZ)修改默认参数;
- 配置类(XXXAutoConfiguration)里配置了核心组件;
引入Druid的stater依赖后,可以在
META-INF
包下的spring.factories
工厂里找到Druid数据源的自动配置类:文章图片
按住“Ctrl+左键”点进去查看
DruidDataSourceAutoConfigure
源码:@Configuration
@ConditionalOnClass(DruidDataSource.class)
@AutoConfigureBefore(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(DruidStatProperties.class, DataSourceProperties.class)
@Import(DruidSpringAopConfiguration.class, DruidStatViewServletConfiguration.class, DruidWebStatFilterConfiguration.class, DruidFilterConfiguration.class)
public class DruidDataSourceAutoConfigure
private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);
public DruidDataSourceAutoConfigure() @Bean(initMethod = "init")
@ConditionalOnMissingBean
public DataSource dataSource()
LOGGER.info("Init DruidDataSource");
return new DruidDataSourceWrapper();
这里有几个需要注意的点:
@AutoConfigureBefore(DataSourseAutoConfiguration.class)
语句的含义是:在SpringBoot自动配置数据源前先配置Druid数据源;这是一个优先级的关系,即Druid场景的自动配置类优先执行;- 原因:官方DataSourseAutoConfiguration里配置了Hikari数据源,只有在容器里没有数据源时才能配置数据源。(详情见本篇2.1点)
@ConditionalOnMissingBean public DataSource dataSource() return new DruidDataSourceWrapper();
- 原因:官方DataSourseAutoConfiguration里配置了Hikari数据源,只有在容器里没有数据源时才能配置数据源。(详情见本篇2.1点)
@Import()
注解给我们导入了以下组件:
DruidSpringAopConfiguration.class
:利用AOP配置SpringBean监控的相关组件;
- 配置项:spring.datasource.druid.aop-patterns
DruidStatViewServletConfiguration.class
:监控页相关配置;
- 配置项:spring.datasource.druid.stat-view-servlet,默认开启
DruidWebStatFilterConfiguration.class
:web监控配置;
- 配置项:spring.datasource.druid.web-stat-filter:默认开启
DruidFilterConfiguration.class
:所有Druid默认filter的配置;
private static final String FILTER_STAT_PREFIX = "spring.datasource.druid.filter.stat"; private static final String FILTER_CONFIG_PREFIX = "spring.datasource.druid.filter.config"; private static final String FILTER_ENCODING_PREFIX = "spring.datasource.druid.filter.encoding"; private static final String FILTER_SLF4J_PREFIX = "spring.datasource.druid.filter.slf4j"; private static final String FILTER_LOG4J_PREFIX = "spring.datasource.druid.filter.log4j"; private static final String FILTER_LOG4J2_PREFIX = "spring.datasource.druid.filter.log4j2"; private static final String FILTER_COMMONS_LOG_PREFIX = "spring.datasource.druid.filter.commons-log"; private static final String FILTER_WALL_PREFIX = "spring.datasource.druid.filterwall";
- 在DataSource的构造方法里,给我们new了一个DruidDataSourceWrapper(Druid数据源包装器);点进去查看源码:
- 可以知道:扩展配置项(绑定属性)在
spring.datasource.druid
里; - 包装器主要作用是读取用户在application文件里的前缀为spring.datasource.druid.XXX,属性为XXX的值,并用这些值对Druid数据源进行配置;
- 可以知道:扩展配置项(绑定属性)在
@ConfigurationProperties("spring.datasource.druid")
class DruidDataSourceWrapper extends DruidDataSource implements InitializingBean
@Autowired
private DataSourceProperties basicProperties;
DruidDataSourceWrapper() public void afterPropertiesSet() throws Exception
if (super.getUsername() == null)
super.setUsername(this.basicProperties.determineUsername());
if (super.getPassword() == null)
super.setPassword(this.basicProperties.determinePassword());
if (super.getUrl() == null)
super.setUrl(this.basicProperties.determineUrl());
if (super.getDriverClassName() == null)
super.setDriverClassName(this.basicProperties.getDriverClassName());
@Autowired(
required = false
)
public void autoAddFilters(List<
Filter>
filters)
super.filters.addAll(filters);
public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis)
try
super.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
catch (IllegalArgumentException var4)
super.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
4. 总结在本篇里我们知道了数据源的自动配置原理,其原理结构图如下:
- org.springframework.boot.autoconfigure.jdbc:SpringBoot自动配置包
- DataSourceAutoConfiguration:数据源的自动配置类;
- DataSourceTransactionManagerAutoConfiguration:事务管理器的自动配置;
- JdbcTemplateAutoConfiguration:JdbcTemplate的自动配置;
- JndiDataSourceAutoConfiguration:jndi的自动配置;
- XADataSourceAutoConfiguration:分布式事务相关的自动配置;
- DruidDataSourceAutoConfigure:Druid数据源自动配置类;
- @AutoConfigureBefore():优先配置Druid数据源;
- @Import():导入组件;
- DruidSpringAopConfiguration.class:利用AOP配置SpringBean监控的相关组件;
- DruidStatViewServletConfiguration.class:监控页相关配置;
- DruidWebStatFilterConfiguration.class:web监控配置;
- DruidFilterConfiguration.class:所有Druid默认filter的配置;
- DruidDataSourceWrapper:Druid数据源包装器;
- 自定义;
- starter(推荐);
- 导入starter场景启动器后,根据SpringBoot的设置模式,首先找到
META-INF
包下的spring.factories
工厂,通过读取EnableAutoConfiguration
获取启动时加载的类 :XXXAutoConfiguration
自动配置类; - 自动配置类会利用
@Bean
注解把场景下相关组件注册进容器中,这些组件的核心配置项会通过@EnableConfigurationProperties
注解跟XXXProperties
配置文件绑定;
- 由此我们可以获得配置类(XXXAutoConfiguration)与配置项(XXXProperties)信息。
- 配置类(XXXAutoConfiguration)里配置了核心组件;
- 配置项(XXXProperties)里主要包含两个信息。其一是通过
@ConfigurationProperties
注解可以获取配置文件的前缀(prefix=Constants.XXX);其二是配置项可修改的参数(YYY)名称及参数(ZZZ)。我们在yml里通过[前缀.参数名称=参数](XXX.YYY=ZZZ)修改默认参数;
新人制作,如有错误,欢迎指出,感激不尽!
:::
::: hljs-center
欢迎关注公众号,会分享一些更日常的东西!
:::
::: hljs-center
如需转载,请标注出处!
:::
::: hljs-center
文章图片
:::
推荐阅读
- <还记得雪花吗;用画图深入理解递归
- <简单分析;汉诺塔问题
- saltstack-master配置文件-----详解#yyds干货盘点#
- #yyds干货盘点#jackson学习之七(常用Field注解)
- 设计模式13-- 模板模式怎么弄()
- saltstack-api日常操作#yyds干货盘点#
- #yyds干货盘点#netty系列之:Bootstrap,ServerBootstrap和netty中的实现
- Centos7 部署 Springboot步骤,小白详细教程,全图
- Egg.js 异常处理中间件jwt,实现接口权限控制