SpringBoot 源码解析 (九)----- Spring Boot的核心能力 - 整合Mybatis
本篇我们在springboot中整合mybatis这个orm框架,毕竟分析一下其自动配置的源码,我们先来回顾一下以前spring中是如何整合mybatis的,大家可以看看我这篇文章mybaits 源码解析 (十)----- spring-mybatis框架使用与源码解析
spring-mybatis使用
添加maven依赖
<dependency> <groupid>org.springframework</groupid> <artifactid>spring-jdbc</artifactid> <version>4.3.8.release</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupid>org.mybatis</groupid> <artifactid>mybatis-spring</artifactid> <version>1.3.2</version> </dependency>
在src/main/resources下添加mybatis-config.xml文件
<?xml version="1.0" encoding="utf-8"?> <!doctype configuration public "-//mybatis.org//dtd config 3.0//en" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typealiases> <typealias alias="user" type="com.chenhao.bean.user" /> </typealiases> <plugins> <plugin interceptor="com.github.pagehelper.pageinterceptor"> <property name="helperdialect" value="mysql"/> </plugin> </plugins> </configuration>
在src/main/resources/mapper路径下添加user.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.chenhao.mapper.usermapper"> <select id="getuser" parametertype="int" resulttype="com.chenhao.bean.user"> select * from user where id = #{id} </select> </mapper>
在src/main/resources/路径下添加beans.xml
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="datasource" class="org.springframework.jdbc.datasource.drivermanagerdatasource"> <property name="driverclassname" value="com.mysql.jdbc.driver"></property> <property name="url" value="jdbc:mysql://127.0.0.1:3306/test"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </bean> <bean id="sqlsessionfactory" class="org.mybatis.spring.sqlsessionfactorybean"> <property name="configlocation" value="classpath:mybatis-config.xml"></property> <property name="datasource" ref="datasource" /> <property name="mapperlocations" value="classpath:mapper/*.xml" /> </bean> <bean class="org.mybatis.spring.mapper.mapperscannerconfigurer"> <property name="basepackage" value="com.chenhao.mapper" /> </bean> </beans>
注解的方式
- 以上分析都是在spring的xml配置文件applicationcontext.xml进行配置的,mybatis-spring也提供了基于注解的方式来配置sqlsessionfactory和mapper接口。
- sqlsessionfactory主要是在@configuration注解的配置类中使用@bean注解的名为sqlsessionfactory的方法来配置;
- mapper接口主要是通过在@configuration注解的配置类中结合@mapperscan注解来指定需要扫描获取mapper接口的包。
@configuration @mapperscan("com.chenhao.mapper") public class appconfig { @bean public datasource datasource() { return new embeddeddatabasebuilder() .addscript("schema.sql") .build(); } @bean public datasourcetransactionmanager transactionmanager() { return new datasourcetransactionmanager(datasource()); } @bean public sqlsessionfactory sqlsessionfactory() throws exception { //创建sqlsessionfactorybean对象 sqlsessionfactorybean sessionfactory = new sqlsessionfactorybean(); //设置数据源 sessionfactory.setdatasource(datasource()); //设置mapper.xml路径 sessionfactory.setmapperlocations(new pathmatchingresourcepatternresolver().getresources("classpath:mapper/*.xml")); // 设置mybatis分页插件 pageinterceptor pageinterceptor = new pageinterceptor(); properties properties = new properties(); properties.setproperty("helperdialect", "mysql"); pageinterceptor.setproperties(properties); sessionfactory.setplugins(new interceptor[]{pageinterceptor}); return sessionfactory.getobject(); } }
最核心的有两点:
- 创建一个sqlsessionfactorybean,并设置数据源和mapper.xml路径,其中会解析mapper.xml文件,最后通过getobject()返回一个sqlsessionfactory 注入spring容器中
- 通过@mapperscan扫描所有mapper接口,扫描过程会将mapper接口生成mapperfactorybean这个特殊的bean,并且在其getobject()通过sqlsession().getmapper(this.mapperinterface)生成每个mapper接口真实的代理类
mapperfactorybean
//最终注入spring容器的就是这里的返回对象 public t getobject() throws exception { //获取父类setsqlsessionfactory方法中创建的sqlsessiontemplate //通过sqlsessiontemplate获取mapperinterface的代理类 //我们例子中就是通过sqlsessiontemplate获取com.chenhao.mapper.usermapper的代理类 //获取到mapper接口的代理类后,就把这个mapper的代理类对象注入spring容器 return this.getsqlsession().getmapper(this.mapperinterface); }
接下来我们看看springboot是如何引入mybatis的
springboot引入mybatis
添加mybatis依赖
<dependency> <groupid>com.alibaba</groupid> <artifactid>druid</artifactid> <version>1.1.9</version> </dependency> <dependency> <groupid>org.mybatis.spring.boot</groupid> <artifactid>mybatis-spring-boot-starter</artifactid> <version>1.3.2</version> </dependency>
全局配置文件中配置数据源和mybatis属性
spring: datasource: url: jdbc:mysql:///springboot username: root password: admin type: com.alibaba.druid.pool.druiddatasource initialsize: 5 minidle: 5 maxactive: 20 mybatis: config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml type-aliases-package: org.com.cay.spring.boot.entity
加入mapper扫描注解@mapperscan
@springbootapplication @enablescheduling @servletcomponentscan @mapperscan("com.supplychain.app.mapper") public class application { public static void main(string[] args) { timezone.setdefault(timezone.gettimezone("gmt+8")); system.setproperty("user.timezone", "gmt+8"); springapplication.run(application.class, args); } }
源码解析
mybatis-spring-boot-starter
我们看到mybatis-spring-boot-starter实际上引入了jdbc的场景启动器,这一块我们上一篇文章已经分析过了,还引入了mybatis-spring的依赖,最终还引入了mybatis-spring-boot-autoconfigure这个依赖,其实mybatis-spring-boot-starter只是引入各种需要的依赖,最核心的代码是在引入的mybatis-spring-boot-autoconfigure这个项目当中,我们来看看这个项目
我们看到mybatis-spring-boot-autoconfigure也像spring-boot-autoconfigure一样配置了spring.factories这个配置文件,并且在配置文件中配置了mybatisautoconfiguration这个自动配置类,我们知道springboot启动时会获取所有spring.factories配置文件中的自动配置类并且进行解析其中的bean,那么我们就来看看mybatisautoconfiguration这个自动配置类做了啥?
mybatisautoconfiguration
1 @org.springframework.context.annotation.configuration 2 @conditionalonclass({ sqlsessionfactory.class, sqlsessionfactorybean.class }) 3 @conditionalonbean(datasource.class) 4 //引入mybatisproperties配置类 5 @enableconfigurationproperties(mybatisproperties.class) 6 @autoconfigureafter(datasourceautoconfiguration.class) 7 public class mybatisautoconfiguration { 8 9 private final mybatisproperties properties; 10 11 private final interceptor[] interceptors; 12 13 private final resourceloader resourceloader; 14 15 private final databaseidprovider databaseidprovider; 16 17 private final list<configurationcustomizer> configurationcustomizers; 18 19 public mybatisautoconfiguration(mybatisproperties properties, 20 objectprovider<interceptor[]> interceptorsprovider, 21 resourceloader resourceloader, 22 objectprovider<databaseidprovider> databaseidprovider, 23 objectprovider<list<configurationcustomizer>> configurationcustomizersprovider) { 24 this.properties = properties; 25 this.interceptors = interceptorsprovider.getifavailable(); 26 this.resourceloader = resourceloader; 27 this.databaseidprovider = databaseidprovider.getifavailable(); 28 this.configurationcustomizers = configurationcustomizersprovider.getifavailable(); 29 } 30 31 @bean 32 @conditionalonmissingbean 33 //往spring容器中注入sqlsessionfactory对象 34 //并且设置数据源、mapperlocations(mapper.xml路径)等 35 public sqlsessionfactory sqlsessionfactory(datasource datasource) throws exception { 36 sqlsessionfactorybean factory = new sqlsessionfactorybean(); 37 factory.setdatasource(datasource); 38 factory.setvfs(springbootvfs.class); 39 if (stringutils.hastext(this.properties.getconfiglocation())) { 40 factory.setconfiglocation(this.resourceloader.getresource(this.properties.getconfiglocation())); 41 } 42 configuration configuration = this.properties.getconfiguration(); 43 if (configuration == null && !stringutils.hastext(this.properties.getconfiglocation())) { 44 configuration = new configuration(); 45 } 46 if (configuration != null && !collectionutils.isempty(this.configurationcustomizers)) { 47 for (configurationcustomizer customizer : this.configurationcustomizers) { 48 customizer.customize(configuration); 49 } 50 } 51 factory.setconfiguration(configuration); 52 if (this.properties.getconfigurationproperties() != null) { 53 factory.setconfigurationproperties(this.properties.getconfigurationproperties()); 54 } 55 if (!objectutils.isempty(this.interceptors)) { 56 factory.setplugins(this.interceptors); 57 } 58 if (this.databaseidprovider != null) { 59 factory.setdatabaseidprovider(this.databaseidprovider); 60 } 61 if (stringutils.haslength(this.properties.gettypealiasespackage())) { 62 factory.settypealiasespackage(this.properties.gettypealiasespackage()); 63 } 64 if (stringutils.haslength(this.properties.gettypehandlerspackage())) { 65 factory.settypehandlerspackage(this.properties.gettypehandlerspackage()); 66 } 67 if (!objectutils.isempty(this.properties.resolvemapperlocations())) { 68 factory.setmapperlocations(this.properties.resolvemapperlocations()); 69 } 70 //获取sqlsessionfactorybean的getobject()中的对象注入spring容器,也就是sqlsessionfactory对象 71 return factory.getobject(); 72 } 73 74 @bean 75 @conditionalonmissingbean 76 //往spring容器中注入sqlsessiontemplate对象 77 public sqlsessiontemplate sqlsessiontemplate(sqlsessionfactory sqlsessionfactory) { 78 executortype executortype = this.properties.getexecutortype(); 79 if (executortype != null) { 80 return new sqlsessiontemplate(sqlsessionfactory, executortype); 81 } else { 82 return new sqlsessiontemplate(sqlsessionfactory); 83 } 84 } 85 86 //other code... 87 }
在自动配置的时候会导入一个properties配置类mybatisproperties,咱们来看一下
@configurationproperties(prefix = mybatisproperties.mybatis_prefix) public class mybatisproperties { public static final string mybatis_prefix = "mybatis"; /** * location of mybatis xml config file. */ private string configlocation; /** * locations of mybatis mapper files. */ private string[] mapperlocations; /** * packages to search type aliases. (package delimiters are ",; \t\n") */ private string typealiasespackage; /** * packages to search for type handlers. (package delimiters are ",; \t\n") */ private string typehandlerspackage; /** * indicates whether perform presence check of the mybatis xml config file. */ private boolean checkconfiglocation = false; /** * execution mode for {@link org.mybatis.spring.sqlsessiontemplate}. */ private executortype executortype; /** * externalized properties for mybatis configuration. */ private properties configurationproperties; /** * a configuration object for customize default settings. if {@link #configlocation} * is specified, this property is not used. */ @nestedconfigurationproperty private configuration configuration; //other code... }
该properties配置类作用主要用于与yml/properties中以mybatis开头的属性进行一一对应,如下
mybatis: config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml type-aliases-package: org.com.cay.spring.boot.entity
<bean id="sqlsessionfactory" class="org.mybatis.spring.sqlsessionfactorybean"> <property name="datasource" ref="datasource"></property> <!-- 自动扫描mapping.xml文件 --> <property name="mapperlocations" value="classpath:com/cn/mapper/*.xml"></property> ... </bean>
另外一个bean为sqlsessiontemplate,通过sqlsessionfactory来生成sqlsession代理类:
public class sqlsessiontemplate implements sqlsession, disposablebean { private final sqlsessionfactory sqlsessionfactory; private final executortype executortype; private final sqlsession sqlsessionproxy; private final persistenceexceptiontranslator exceptiontranslator; //other code... public sqlsessiontemplate(sqlsessionfactory sqlsessionfactory, executortype executortype, persistenceexceptiontranslator exceptiontranslator) { notnull(sqlsessionfactory, "property 'sqlsessionfactory' is required"); notnull(executortype, "property 'executortype' is required"); this.sqlsessionfactory = sqlsessionfactory; this.executortype = executortype; this.exceptiontranslator = exceptiontranslator; //生成sqlsessioin代理类 this.sqlsessionproxy = (sqlsession) newproxyinstance( sqlsessionfactory.class.getclassloader(), new class[] { sqlsession.class }, new sqlsessioninterceptor()); } }
而@mapperscan注解是和spring整合mybatis的使用是一样的,都是在配置类上指定mapper接口的路径,大家可以看一下我以前的一篇文章mybaits 源码解析 (十一)----- @mapperscan将mapper接口生成代理注入到spring-静态代理和动态代理结合使用
日常求赞
好了各位,以上就是这篇文章的全部内容了,能看到这里的人呀,都是人才。
如果这个文章写得还不错,觉得学到了一点东西的话 求点赞
上一篇: 2、解构赋值
推荐阅读
-
SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - SpringBoot如何实现SpringMvc的?
-
SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)
-
SpringBoot 源码解析 (九)----- Spring Boot的核心能力 - 整合Mybatis
-
SpringBoot 源码解析 (五)----- Spring Boot的核心能力 - 自动配置源码解析
-
SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)
-
SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - SpringBoot如何实现SpringMvc的?
-
SpringBoot 源码解析 (五)----- Spring Boot的核心能力 - 自动配置源码解析
-
SpringBoot 源码解析 (九)----- Spring Boot的核心能力 - 整合Mybatis
-
Springboot整合MyBatis, yml配置,超详细从mybatis-spring-boot-starter根据源码进行配置,MybatisProperties类中的属性【源码版】)