本文则针对数据库的连接配置作下简单的分析,方便笔者理解以及后续的查阅

栗子当先

以我们经常用的mybatis数据库持久框架来操作mysql服务为例


环境依赖

1.JDK v1.8+
2.springboot v2.0.3.RELEASE
3.mybatis v3.4.6
4.mysql v10.2.8-MarialDB

配置类步骤

1.pom.xml

<!--mybatis-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.40</version>
</dependency>

2.springboot配置 application-datasource.properties

#datasource config
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/boot?useSSL=false&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimeZone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456#mybatis config
mybatis.check-config-location=false
mybatis.mapper-locations=classpath*:database/mybatis/mapper/*.xml
mybatis.executor-type=reuse

代码栗子步骤

1.实体类User.java

package com.example.demo.database.entity;/*** @author nanco* -------------* demo-springboot* -------------* @create 2018/10/17 16:52**/
public class User {private Long id ;private String name ;private Integer age ;private String email ;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", email='" + email + '\'' +'}';}
}

2.mapper配置文件 UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.example.demo.database.mysql.dao.UserDao"><insert id="saveUser" parameterType="com.example.demo.database.entity.User">insert into tbl_user(name,age,email)values(#{name},#{age},#{email})</insert>
</mapper>

3.为了使上述配置生效,则须定义扫描入口(@MapperScan)

package com.example.demo.database.config;import com.mysql.jdbc.Driver;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;/*** @author nanco* -------------* demo-springboot* -------------* @create 2018/10/17 17:09**/
@Configuration
public class DatabaseConfig {@Configuration@ConditionalOnClass(Driver.class)@MapperScan("com.example.demo.database.mysql.dao")static class MysqlInterfaceScanner {}
}

4.来一个测试类

package com.example.demo.database.mysql;import com.example.demo.database.DatabaseApplication;
import com.example.demo.database.entity.User;
import com.example.demo.database.mysql.dao.UserDao;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.Assert;import javax.annotation.Resource;/*** @author nanco* -------------* demo-springboot* -------------* @create 2018/10/17 17:13**/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {DatabaseApplication.class})
public class MysqlDaoTest {@Resourceprivate UserDao userDao;@Testpublic void testSave() {User user = new User();user.setName("nanco");user.setAge(18);user.setEmail("nancoasky@gmail.com");System.out.println(userDao.saveUser(user));}
}

运行上述的测试案例便完成了简单的插入功能,其他的功能读者可自行编写

源码层

查阅了spring-boot-autoconfigure包下的spring.factories,发现对于数据源的配置是通过DataSourceAutoConfiguration类来进行的,由此简单的展开下

DataSourceAutoConfiguration

本类的注册是有条件的,其类上的注解是

@Configuration
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class })
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({ DataSourcePoolMetadataProvidersConfiguration.class,DataSourceInitializationConfiguration.class })

其中DataSource类是JDK自带的,EmbeddedDatabaseType类则是依赖spring-jdbc包,本例中引入mybatis则默认带入了上述包。笔者按照@Configuration的加载顺序来对此类作下简单的分析

1.静态内部类注册解析


数据源检测

    @Configuration@Conditional(EmbeddedDatabaseCondition.class)@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })@Import(EmbeddedDataSourceConfiguration.class)protected static class EmbeddedDatabaseConfiguration {}

具体的代码读者可翻阅相应的文档,这里作下总结

  • 用户配置了spring.datasource.type属性或者classpath下存在springboot默认支持的数据源则该配置略过
    1) com.zaxxer.hikari.HikariDataSource
    2) org.apache.tomcat.jdbc.pool.DataSource
    3) org.apache.commons.dbcp2.BasicDataSource

  • 如果上述的条件不满足则会在classpath下找寻springboot默认支持的数据库驱动,存在则会创建SimpleDriverDataSource数据源用来创建数据库连接
    1) H2 Database
    2) Derby Database
    3) HSQL Database

本例中引入mybatis-spring-boot-starter便会引入spring-jdbc包,则会采用HikariDataSource数据源来获取数据库连接


数据源创建

    @Configuration@Conditional(PooledDataSourceCondition.class)@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.Generic.class,DataSourceJmxConfiguration.class })protected static class PooledDataSourceConfiguration {}

根据用户配置的spring.datasource.type属性或者springboot默认支持的数据源(见上)来进行数据源对象的创建,具体的读者可自行阅读,本例中则会采取HikariDataSource数据源,并注入至bean工厂中,当然也可以通过配置项给予更多的属性配置

spring.datasource.hikari.max-wait-millis=10000
spring.datasource.hikari.min-idle=5
spring.datasource.hikari.initial-size=5
spring.datasource.hikari.validation-query=SELECT 1

2.导入类解析


数据库连接池状态类初始化

@Configuration
public class DataSourcePoolMetadataProvidersConfiguration {@Configuration@ConditionalOnClass(HikariDataSource.class)static class HikariPoolDataSourceMetadataProviderConfiguration {@Beanpublic DataSourcePoolMetadataProvider hikariPoolDataSourceMetadataProvider() {return (dataSource) -> {if (dataSource instanceof HikariDataSource) {return new HikariDataSourcePoolMetadata((HikariDataSource) dataSource);}return null;};}}
}

HikariDataSource为例,则会创建HikariDataSourcePoolMetadata对象,主要是用来获取连接池的相关信息,看下DataSourcePoolMetadata接口就行,具体如下

public interface DataSourcePoolMetadata {/*** Return the usage of the pool as value between 0 and 1 (or -1 if the pool is not* limited).* <ul>* <li>1 means that the maximum number of connections have been allocated</li>* <li>0 means that no connection is currently active</li>* <li>-1 means there is not limit to the number of connections that can be allocated* </li>* </ul>* This may also return {@code null} if the data source does not provide the necessary* information to compute the poll usage.* @return the usage value or {@code null}*/Float getUsage();/*** Return the current number of active connections that have been allocated from the* data source or {@code null} if that information is not available.* @return the number of active connections or {@code null}*/Integer getActive();/*** Return the maximum number of active connections that can be allocated at the same* time or {@code -1} if there is no limit. Can also return {@code null} if that* information is not available.* @return the maximum number of active connections or {@code null}*/Integer getMax();/*** Return the minimum number of idle connections in the pool or {@code null} if that* information is not available.* @return the minimum number of active connections or {@code null}*/Integer getMin();/*** Return the query to use to validate that a connection is valid or {@code null} if* that information is not available.* @return the validation query or {@code null}*/String getValidationQuery();/*** The default auto-commit state of connections created by this pool. If not set* ({@code null}), default is JDBC driver default (If set to null then the* java.sql.Connection.setAutoCommit(boolean) method will not be called.)* @return the default auto-commit state or {@code null}*/Boolean getDefaultAutoCommit();}

sql脚本执行加载

@Configuration
@Import({ DataSourceInitializerInvoker.class,DataSourceInitializationConfiguration.Registrar.class })
class DataSourceInitializationConfiguration {
}

主要通过DataSourceInitializerInvoker类来进行sql脚本的执行加载,具体笔者就不贴代码了,作下简单的总结
1) 如果spring.datasource.schema属性已指定相应的sql文件,则优先读取,并支持classpath路径查找
2) 如果上述无配置,则默认读取classpath*:schema.sql/classpath*:schema-${platform}.sql文件(其中${platform}可用spring.datasource.platform指定)
3) 如果没有上述文件,则不执行

温馨提示:如果想在环境运行的时候执行相应的sql语句,则仍需要另外配置用户名(spring.datasource.schema-username)与密码(spring.datasource.schema-password),方可执行

MybatisAutoConfiguration

其加载顺序是在上述的DataSourceAutoConfiguration之后的,看它头上的注解便可得知。读者在这之前最好已经了解了mybatis在spring中的相关用法,比如SqlsessionFactoryMappedStatement等基本概念,不了解也可直接戳笔者的先前文章Spring mybatis源码学习指引目录。

springboot支持用户使用@MapperScan或者@Mapper注解来注册扫描相应的dao接口。后者只能应用于单个的数据源,一般推荐使用前者来进行扫描注册,因为前者有更多的属性配置。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {/*** Alias for the {@link #basePackages()} attribute. Allows for more concise* annotation declarations e.g.:* {@code @EnableMyBatisMapperScanner("org.my.pkg")} instead of {@code* @EnableMyBatisMapperScanner(basePackages= "org.my.pkg"})}.*/String[] value() default {};/*** Base packages to scan for MyBatis interfaces. Note that only interfaces* with at least one method will be registered; concrete classes will be* ignored.*/String[] basePackages() default {};/*** Type-safe alternative to {@link #basePackages()} for specifying the packages* to scan for annotated components. The package of each class specified will be scanned.* <p>Consider creating a special no-op marker class or interface in each package* that serves no purpose other than being referenced by this attribute.*/Class<?>[] basePackageClasses() default {};/*** The {@link BeanNameGenerator} class to be used for naming detected components* within the Spring container.*/Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;/*** This property specifies the annotation that the scanner will search for.* <p>* The scanner will register all interfaces in the base package that also have* the specified annotation.* <p>* Note this can be combined with markerInterface.*/Class<? extends Annotation> annotationClass() default Annotation.class;/*** This property specifies the parent that the scanner will search for.* <p>* The scanner will register all interfaces in the base package that also have* the specified interface class as a parent.* <p>* Note this can be combined with annotationClass.*/Class<?> markerInterface() default Class.class;/*** Specifies which {@code SqlSessionTemplate} to use in the case that there is* more than one in the spring context. Usually this is only needed when you* have more than one datasource.*/String sqlSessionTemplateRef() default "";/*** Specifies which {@code SqlSessionFactory} to use in the case that there is* more than one in the spring context. Usually this is only needed when you* have more than one datasource.*/String sqlSessionFactoryRef() default "";/*** Specifies a custom MapperFactoryBean to return a mybatis proxy as spring bean.**/Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class;}

详细的属性注释也拷贝过来了,其可以针对不同的数据源扫描注册相应的dao接口,适用于多数据源应用。具体使用笔者就不展开了,具体看下其@MapperScan注解是如何被解析的,直接看MapperScannerRegistrar#registerBeanDefinitions()注册方法

  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);// this check is needed in Spring 3.1if (resourceLoader != null) {scanner.setResourceLoader(resourceLoader);}Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");if (!Annotation.class.equals(annotationClass)) {scanner.setAnnotationClass(annotationClass);}Class<?> markerInterface = annoAttrs.getClass("markerInterface");if (!Class.class.equals(markerInterface)) {scanner.setMarkerInterface(markerInterface);}Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");if (!BeanNameGenerator.class.equals(generatorClass)) {scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));}Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));}scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef"));List<String> basePackages = new ArrayList<String>();for (String pkg : annoAttrs.getStringArray("value")) {if (StringUtils.hasText(pkg)) {basePackages.add(pkg);}}for (String pkg : annoAttrs.getStringArray("basePackages")) {if (StringUtils.hasText(pkg)) {basePackages.add(pkg);}}for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {basePackages.add(ClassUtils.getPackageName(clazz));}scanner.registerFilters();scanner.doScan(StringUtils.toStringArray(basePackages));}

说白了也就是通过mybatis的接口扫描类ClassPathMapperScanner类进行具体的处理,很简单。具体的解析步骤可详细戳上述的文章链接

小结

mybatis属性在springboot的使用,笔者并没有展开,读者可详看MybatisProperties类便可。笔者发现过多冗长的代码会影响笔者乃至读者的回看,于是笔者决定后续的文章,笔者尽可能详细记录自己的思考步骤,至于代码就贴出相应的关键部分即可方便后续回看~

转载于:https://www.cnblogs.com/question-sky/p/9816829.html

springboot情操陶冶-web配置(六)相关推荐

  1. springboot情操陶冶-web配置(四)

    承接前文springboot情操陶冶-web配置(三),本文将在DispatcherServlet应用的基础上谈下websocket的使用 websocket websocket的简单了解可见维基百科 ...

  2. springboot情操陶冶-web配置(八)

    本文关注应用的安全方面,涉及校验以及授权方面,以springboot自带的security板块作为讲解的内容 实例 建议用户可直接路由至博主的先前博客spring security整合cas方案.本文 ...

  3. springboot情操陶冶-@SpringBootApplication注解解析

    承接前文springboot情操陶冶-@Configuration注解解析,本文将在前文的基础上对@SpringBootApplication注解作下简单的分析 @SpringBootApplicat ...

  4. SpringBoot深入(一)--SpringBoot内置web容器及配置

    版权声明:作者原创,转载请注明出处. 本系列文章目录地址:http://blog.csdn.net/u011961421/article/details/79416510 前言 在学会基本运用Spri ...

  5. Springboot环境下mybatis配置多数据源配置

    mybatis多数据源配置(本文示例为两个),方便实现数据库的读写分离,分库分表功能 本文基于springboot2进行的配置,如版本为springboot1系列则需修改yml的配置(在文末附带) m ...

  6. 轻松搭建基于 SpringBoot Vue 的 Web 商城应用

    背景介绍 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数 ...

  7. Spring Boot——自定义Web配置类后无法访问/static文件夹下静态资源

    问题描述 自定义Web配置类后无法访问 /static文件夹下静态资源. 已加相关依赖包. 官方文档 Spring MVC Auto Configuration Maven <dependenc ...

  8. SpringBoot默认日志logback配置解析

    SpringBoot默认日志logback配置解析 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的,你呢 如何引入日志? 日志输出格式 ...

  9. SpringBoot ——Spring Boot日志配置

    Spring Boot 采用了 slf4j+logback 的组合形式,Spring Boot也提供对JUL.log4j2.Logback提供了默认配置 1.默认日志配置 修改日志默认级别 2.修改日 ...

  10. Serverless 实战 —— 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用

    Serverless 实战 -- 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用 背景介绍 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute ...

最新文章

  1. decltype判断变量或表达式类型
  2. C++极值minmax最大值最小值算法(附完整源码)
  3. turtle 20秒画完小猪佩奇“社会人”
  4. Pytorch class 中 的__call__方法
  5. UVA12468 Zapping【水题】
  6. 计算机控制系统功能,计算机控制系统功能之操作指导-电脑自学网
  7. 论文推荐到计算机科学期刊,计算机类论文参考文献推荐 计算机类核心期刊参考文献哪里找...
  8. 我用Python的Matplotlib库绘制25个超好看图表
  9. 电子邮件是qq邮箱吗
  10. 亚马逊森林大火----- 我也来评论一下
  11. 计算机需要权限来执行此操作 win7,win7系统删除提示“文件夹访问被拒绝,需要权限执行此操作”怎么办...
  12. Python-阿里云地图的爬取
  13. 《位置大数据隐私管理》—— 导读
  14. 从 Angular Component 和 Directive 的实例化,谈谈 Angular forRoot 方法的命令由来
  15. 【FI】SAP 付款及清账
  16. 内存走线 菊花链_[转帖]关于DDR4内存颗粒、单双面、主板布线和双通道的那些事儿...
  17. [T-ARA][TIAMO]
  18. c语言改错题字符串a放在b后面,C语言程序改错题汇总.doc
  19. 目标检测学习笔记2——ResNet残差网络学习、ResNet论文解读
  20. 我还是很喜欢你,像相思藏在树底, 花落是你,花开也是你。

热门文章

  1. kotlin支持jdk1.8编译,使用Java8特性
  2. Ubuntu 10.04编译安装insigh-6.8-1
  3. keepalived高可用配置注意事项
  4. 【离散数学2】代数系统趣题
  5. KeyMob聚合致力于为广大开发者及广告聚合服务
  6. Web开发:Apache2.2.x+Tomcat6.x+jk2.x做集群配置
  7. Mozilla推动互联网成为游戏发展的强有力平台
  8. mysql5.7.12无法启动_MySql5.7.12免安装版配置以及服务无法启动问题解决方法
  9. 和is哪个好_眼霜哪个牌子好用?这些品牌的眼霜睡前涂一涂,黑眼圈细纹没有了...
  10. libcurl学习及简易封装类