当前位置: 首页 > news >正文

Spring Boot如何整合mybatis

文章目录

  • 1. 相关配置和代码
  • 2. 整合原理
    • 2.1 springboot自动配置
    • 2.2 MybatisAutoConfiguration
    • 2.3 debug过程
      • 2.3.1 AutoConfiguredMapperScannerRegistrar
      • 2.3.2 MapperScannerConfigurer
      • 2.3.4 创建MapperFactoryBean
      • 2.3.5 创建MybatisAutoConfiguration
      • 2.3.6 创建sqlSessionFactory
      • 2.3.7 创建SqlSessionTemplate
      • 2.3.8 mapper接口代理对象创建

1. 相关配置和代码

  • maven配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.14</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.boge</groupId><artifactId>mybatis-spring-boot</artifactId><version>0.0.1-SNAPSHOT</version><name>mybatis-spring-boot</name><description>mybatis-spring-boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.18</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter-test</artifactId><version>2.3.1</version><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
  • application.yml
server:port: 8000
spring:main:allow-circular-references: trueallow-bean-definition-overriding: trueapplication:name: freedom-codedatasource:type: com.alibaba.druid.pool.DruidDataSource# MYSQL 5 驱动:com.mysql.jdbc.Driver,MYSQL 6+ 驱动:com.mysql.cj.jdbc.Driverdriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatis-vip?characterEncoding=utf-8&serverTimezone=UTCusername: rootpassword: WSX2952fcx!druid:# 初始化大小,最小,最大initial-size: 5min-idle: 5max-active: 100# 配置获取连接等待超时的时间max-wait: 60000# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒time-between-eviction-runs-millis: 60000# 配置一个连接在池中最小生存时间min-evictable-idle-time-millis: 300000validation-query: select VERSION()test-while-idle: truetest-on-borrow: falsetest-on-return: falsemybatis:# xml映射文件mapper-locations: "classpath:mapper/*.xml"type-aliases-package: "com.boge.pojo"configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true
  • 代码
@Mapper
public interface UserMapper {List<User> query();
}
@SpringBootApplication
public class MybatisSpringBootApplication {public static void main(String[] args) {SpringApplication.run(MybatisSpringBootApplication.class, args);}}

测试代码

@SpringBootTest
class MybatisSpringBootApplicationTests {@Autowiredprivate IUserService iUserService;@Testvoid contextLoads() {for (User user : iUserService.query()) {System.out.println(user);}}}

2. 整合原理

关注三个对象的创建:

  • SqlSessionFactory如何创建
  • SqlSession如何创建
  • Mapper接口的代理类如何创建(比如UserMapper)。

2.1 springboot自动配置

原理略。
在这里插入图片描述

2.2 MybatisAutoConfiguration

源码。

/**    Copyright 2015-2022 the original author or authors.**    Licensed under the Apache License, Version 2.0 (the "License");*    you may not use this file except in compliance with the License.*    You may obtain a copy of the License at**       https://www.apache.org/licenses/LICENSE-2.0**    Unless required by applicable law or agreed to in writing, software*    distributed under the License is distributed on an "AS IS" BASIS,*    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*    See the License for the specific language governing permissions and*    limitations under the License.*/
package org.mybatis.spring.boot.autoconfigure;/*** {@link EnableAutoConfiguration Auto-Configuration} for Mybatis. Contributes a {@link SqlSessionFactory} and a* {@link SqlSessionTemplate}. If {@link org.mybatis.spring.annotation.MapperScan} is used, or a configuration file is* specified as a property, those will be considered, otherwise this auto-configuration will attempt to register mappers* based on the interface definitions in or under the root auto-configuration package.** @author Eddú Meléndez* @author Josh Long* @author Kazuki Shimizu* @author Eduardo Macarrón*/
@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration implements InitializingBean {private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);private final MybatisProperties properties;private final Interceptor[] interceptors;private final TypeHandler[] typeHandlers;private final LanguageDriver[] languageDrivers;private final ResourceLoader resourceLoader;private final DatabaseIdProvider databaseIdProvider;private final List<ConfigurationCustomizer> configurationCustomizers;private final List<SqlSessionFactoryBeanCustomizer> sqlSessionFactoryBeanCustomizers;public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider,ObjectProvider<TypeHandler[]> typeHandlersProvider, ObjectProvider<LanguageDriver[]> languageDriversProvider,ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider,ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider,ObjectProvider<List<SqlSessionFactoryBeanCustomizer>> sqlSessionFactoryBeanCustomizers) {this.properties = properties;this.interceptors = interceptorsProvider.getIfAvailable();this.typeHandlers = typeHandlersProvider.getIfAvailable();this.languageDrivers = languageDriversProvider.getIfAvailable();this.resourceLoader = resourceLoader;this.databaseIdProvider = databaseIdProvider.getIfAvailable();this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();this.sqlSessionFactoryBeanCustomizers = sqlSessionFactoryBeanCustomizers.getIfAvailable();}@Overridepublic void afterPropertiesSet() {checkConfigFileExists();}private void checkConfigFileExists() {if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());Assert.state(resource.exists(),"Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)");}}@Bean@ConditionalOnMissingBeanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factory = new SqlSessionFactoryBean();factory.setDataSource(dataSource);factory.setVfs(SpringBootVFS.class);if (StringUtils.hasText(this.properties.getConfigLocation())) {factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));}applyConfiguration(factory);if (this.properties.getConfigurationProperties() != null) {factory.setConfigurationProperties(this.properties.getConfigurationProperties());}if (!ObjectUtils.isEmpty(this.interceptors)) {factory.setPlugins(this.interceptors);}if (this.databaseIdProvider != null) {factory.setDatabaseIdProvider(this.databaseIdProvider);}if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());}if (this.properties.getTypeAliasesSuperType() != null) {factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());}if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());}if (!ObjectUtils.isEmpty(this.typeHandlers)) {factory.setTypeHandlers(this.typeHandlers);}Resource[] mapperLocations = this.properties.resolveMapperLocations();if (!ObjectUtils.isEmpty(mapperLocations)) {factory.setMapperLocations(mapperLocations);}Set<String> factoryPropertyNames = Stream.of(new BeanWrapperImpl(SqlSessionFactoryBean.class).getPropertyDescriptors()).map(PropertyDescriptor::getName).collect(Collectors.toSet());Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {// Need to mybatis-spring 2.0.2+factory.setScriptingLanguageDrivers(this.languageDrivers);if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {defaultLanguageDriver = this.languageDrivers[0].getClass();}}if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {// Need to mybatis-spring 2.0.2+factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);}applySqlSessionFactoryBeanCustomizers(factory);return factory.getObject();}private void applyConfiguration(SqlSessionFactoryBean factory) {Configuration configuration = this.properties.getConfiguration();if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {configuration = new Configuration();}if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {for (ConfigurationCustomizer customizer : this.configurationCustomizers) {customizer.customize(configuration);}}factory.setConfiguration(configuration);}private void applySqlSessionFactoryBeanCustomizers(SqlSessionFactoryBean factory) {if (!CollectionUtils.isEmpty(this.sqlSessionFactoryBeanCustomizers)) {for (SqlSessionFactoryBeanCustomizer customizer : this.sqlSessionFactoryBeanCustomizers) {customizer.customize(factory);}}}@Bean@ConditionalOnMissingBeanpublic SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {ExecutorType executorType = this.properties.getExecutorType();if (executorType != null) {return new SqlSessionTemplate(sqlSessionFactory, executorType);} else {return new SqlSessionTemplate(sqlSessionFactory);}}/*** This will just scan the same base package as Spring Boot does. If you want more power, you can explicitly use* {@link org.mybatis.spring.annotation.MapperScan} but this will get typed mappers working correctly, out-of-the-box,* similar to using Spring Data JPA repositories.*/public static class AutoConfiguredMapperScannerRegistrarimplements BeanFactoryAware, EnvironmentAware, ImportBeanDefinitionRegistrar {private BeanFactory beanFactory;private Environment environment;@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {if (!AutoConfigurationPackages.has(this.beanFactory)) {logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");return;}logger.debug("Searching for mappers annotated with @Mapper");List<String> packages = AutoConfigurationPackages.get(this.beanFactory);if (logger.isDebugEnabled()) {packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg));}BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);builder.addPropertyValue("processPropertyPlaceHolders", true);builder.addPropertyValue("annotationClass", Mapper.class);builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);Set<String> propertyNames = Stream.of(beanWrapper.getPropertyDescriptors()).map(PropertyDescriptor::getName).collect(Collectors.toSet());if (propertyNames.contains("lazyInitialization")) {// Need to mybatis-spring 2.0.2+builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");}if (propertyNames.contains("defaultScope")) {// Need to mybatis-spring 2.0.6+builder.addPropertyValue("defaultScope", "${mybatis.mapper-default-scope:}");}// for spring-nativeboolean injectSqlSession = environment.getProperty("mybatis.inject-sql-session-on-mapper-scan", Boolean.class,Boolean.TRUE);if (injectSqlSession && this.beanFactory instanceof ListableBeanFactory) {ListableBeanFactory listableBeanFactory = (ListableBeanFactory) this.beanFactory;Optional<String> sqlSessionTemplateBeanName = Optional.ofNullable(getBeanNameForType(SqlSessionTemplate.class, listableBeanFactory));Optional<String> sqlSessionFactoryBeanName = Optional.ofNullable(getBeanNameForType(SqlSessionFactory.class, listableBeanFactory));if (sqlSessionTemplateBeanName.isPresent() || !sqlSessionFactoryBeanName.isPresent()) {builder.addPropertyValue("sqlSessionTemplateBeanName",sqlSessionTemplateBeanName.orElse("sqlSessionTemplate"));} else {builder.addPropertyValue("sqlSessionFactoryBeanName", sqlSessionFactoryBeanName.get());}}builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());}@Overridepublic void setBeanFactory(BeanFactory beanFactory) {this.beanFactory = beanFactory;}@Overridepublic void setEnvironment(Environment environment) {this.environment = environment;}private String getBeanNameForType(Class<?> type, ListableBeanFactory factory) {String[] beanNames = factory.getBeanNamesForType(type);return beanNames.length > 0 ? beanNames[0] : null;}}/*** If mapper registering configuration or mapper scanning configuration not present, this configuration allow to scan* mappers based on the same component-scanning path as Spring Boot itself.*/@org.springframework.context.annotation.Configuration@Import(AutoConfiguredMapperScannerRegistrar.class)@ConditionalOnMissingBean({ MapperFactoryBean.class, MapperScannerConfigurer.class })public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {@Overridepublic void afterPropertiesSet() {logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");}}}

2.3 debug过程

按照代码的执行顺序。

2.3.1 AutoConfiguredMapperScannerRegistrar

主要是为MapperScannerConfigurer定制bean信息。

@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {if (!AutoConfigurationPackages.has(this.beanFactory)) {logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");return;}logger.debug("Searching for mappers annotated with @Mapper");// 获得基本的包List<String> packages = AutoConfigurationPackages.get(this.beanFactory);if (logger.isDebugEnabled()) {packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg));}// 定制属性值BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);builder.addPropertyValue("processPropertyPlaceHolders", true);builder.addPropertyValue("annotationClass", Mapper.class);builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(packages));BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class);Set<String> propertyNames = Stream.of(beanWrapper.getPropertyDescriptors()).map(PropertyDescriptor::getName).collect(Collectors.toSet());if (propertyNames.contains("lazyInitialization")) {// Need to mybatis-spring 2.0.2+builder.addPropertyValue("lazyInitialization", "${mybatis.lazy-initialization:false}");}if (propertyNames.contains("defaultScope")) {// Need to mybatis-spring 2.0.6+builder.addPropertyValue("defaultScope", "${mybatis.mapper-default-scope:}");}// for spring-nativeboolean injectSqlSession = environment.getProperty("mybatis.inject-sql-session-on-mapper-scan", Boolean.class,Boolean.TRUE);if (injectSqlSession && this.beanFactory instanceof ListableBeanFactory) {ListableBeanFactory listableBeanFactory = (ListableBeanFactory) this.beanFactory;Optional<String> sqlSessionTemplateBeanName = Optional.ofNullable(getBeanNameForType(SqlSessionTemplate.class, listableBeanFactory));Optional<String> sqlSessionFactoryBeanName = Optional.ofNullable(getBeanNameForType(SqlSessionFactory.class, listableBeanFactory));if (sqlSessionTemplateBeanName.isPresent() || !sqlSessionFactoryBeanName.isPresent()) {builder.addPropertyValue("sqlSessionTemplateBeanName",sqlSessionTemplateBeanName.orElse("sqlSessionTemplate"));} else {builder.addPropertyValue("sqlSessionFactoryBeanName", sqlSessionFactoryBeanName.get());}}builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// 放入BeanDefiniotn注册中心registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());}

在这里插入图片描述

在这里插入图片描述

2.3.2 MapperScannerConfigurer

MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor。
方法postProcessBeanDefinitionRegistry可以修改beanDefinition信息。为mapper接口定制beanDefinition。

在这里插入图片描述
在这里插入图片描述
进入processBeanDefinitions方法
在这里插入图片描述
在这里插入图片描述

2.3.4 创建MapperFactoryBean

在这里插入图片描述

2.3.5 创建MybatisAutoConfiguration

在这里插入图片描述

2.3.6 创建sqlSessionFactory

这里还是利用SqlSessionFactoryBean来创建sqlSessionFactory的bean对象。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3.7 创建SqlSessionTemplate

在这里插入图片描述

2.3.8 mapper接口代理对象创建

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

http://www.lryc.cn/news/111733.html

相关文章:

  • TypeScript中 interface 和 type 的区别
  • 题解 | #B.Distance# 2023牛客暑期多校6
  • 【flink】开启savepoint
  • 【C++】开源:事件驱动网络库libevent配置使用
  • 业务测试——历史数据
  • 【Linux】计算机网络套接字编写
  • Maven-学习笔记
  • WebGL Shader着色器GLSL语言
  • 【Codeforces】 CF468C Hack it!
  • FFmpeg常见命令行(一):FFmpeg工具使用基础
  • Mock.js的基本使用方法
  • TiDB 源码编译之 PD/TiDB Dashboard 篇
  • Vue3描述列表(Descriptions)
  • 【驱动开发day8作业】
  • yxBUG记录
  • uniapp引入inconfont自定义导航栏
  • OSLog与NSLog对比
  • 全网最细,Fiddler修改接口返回数据详细步骤实战,辅助接口测试...
  • Mysql自动同步的详细设置步骤
  • opencv-38 形态学操作-闭运算(先膨胀,后腐蚀)cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
  • jenkins gitlab多分支构建发布
  • 刷题笔记 day8
  • C 语言的表达式
  • C++设计模式创建型之单例模式
  • 杂记 | 记录一次使用Docker安装gitlab-ce的过程(含配置交换内存)
  • MyBatis@Param注解的用法
  • Shader 编程:GLSL 重要的内置函数
  • 浏览器同源策略
  • GD32F103的EXTI中断和EXTI事件
  • 了解 spring MVC + 使用spring MVC - springboot