springboot 集成 mybatis 原理分析

springboot 集成 mybatis 原理分析,第1张

springboot 集成 mybatis 原理分析

参考 https://blog.csdn.net/weixin_39854681/article/details/110859474

springboot 集成 mybatis 1、配置 maven 依赖
 	
	
		org.mybatis.spring.boot
		mybatis-spring-boot-starter
	
2、application.yml配置文件
###服务器配置
server:
  port: 9001
 
spring:
  application:
    name: user
 
  ###druid数据源配置
  datasource:
    name: dataSource
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/imalvisc?useSSL=false
    username: root
    password: imalvisc
    druid:
      initial-size: 5
	  .................
 
###mybatis数据源配置
mybatis:
  type-aliases-package: com.imalvisc.spring.mybatis.model
  configuration:
    map-underscore-to-camel-case: true
3、启动类
package com.imalvisc.spring.mybatis;
 
import com.imalvisc.spring.mybatis.mapper.UserInfoMapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
 
@SpringBootApplication
@MapperScan(basePackages = {"com.imalvisc.spring.mybatis.mapper"})
public class Application {
 
    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
        UserInfoMapper userInfoMapper = applicationContext.getBean(UserInfoMapper.class);
        System.out.println(userInfoMapper.selectAll());
    }
}

以上就已经将 springboot 集成 mybatis 环境搭建完成

原理分析

项目中引入了 mybatis-spring-boot-starter 依赖,所以间接引入了 mybatis-spring-boot-autoconfigure ,在 mybatis-spring-boot-autoconfigure 的类路径下,看到 meta-INF 目录下有一个 spring.factories 文件,文件内容是个类似键值对的配置,key 是 EnableAutoConfiguration ,值是 mybatis 的配置类如下

注意: springboot 项目启动时,会扫描项目本身及依赖的【所有 jar 包】类路径下的 meta-INF 目录的 spring.factories 文件,再根据文件内容中的【全限定类名】找到并加载执行该类,这就是 springboot 自动配置的真谛。

上述键值对的值中一个类是 MybatisLanguageDriverAutoConfiguration

注解含义

// 相当于
@org.springframework.context.annotation.Configuration

// 当前classpath路径下面是否存在 SqlSessionFactory.class, SqlSessionFactoryBean.class,存在则
// 进行将当前配置装载到spring容器中
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })

// 相当于 beanFactory.getBeanByType(javax.sql.DataSource.class)
@ConditionalOnBean(DataSource.class)

// 让用了 @ConfigurationProperties 注解的类生效并将该类注入到 IOC 容器中,交由 IOC 容器进行管理
// MybatisProperties 是 yml 中 mybatis 配置属性的实体映射,该类用了 @ConfigurationProperties 
@EnableConfigurationProperties(MybatisProperties.class)

// 顺序在DataSourceAutoConfiguration.class之后
@AutoConfigureAfter(DataSourceAutoConfiguration.class)

其他 Conditional 注解

@Conditional(TestCondition.class)

这句代码可以标注在类上面,表示该类下面的所有 @Bean 都会启用配置,也可以标注在方法上面,只是对该方法启用配置。

@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个 Bean)

@ConditionalOnClass(某个 class 位于类路径上,才会实例化一个 Bean)
@ConditionalOnSingleCandidate(DataSource.class) IOC 容器中只有一个指定的候选对象才起作用

@ConditionalOnexpression(当表达式为true的时候,才会实例化一个 Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个 Bean)
@ConditionalOnMissingClass(某个 class 类路径上不存在的时候,才会实例化一个 Bean)
@ConditionalOnNotWebApplication(不是web应用)

这是一个 Configuration 类,@AutoConfigureAfter(DataSourceAutoConfiguration.class) 代表在DataSourceAutoConfiguration 类加载完后再加载,因为 mybatis 要依赖数据源配置,要在数据源配置完成后才进行 mybatis 配置。在 MybatisAutoConfiguration 类中,配置了 SqlSessionFactory类,所在到这里 mybatis 的环境就已经生效了。

  @Bean
  @ConditionalOnMissingBean
  public 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.properties.resolveMapperLocations())) {
      factory.setMapperLocations(this.properties.resolveMapperLocations());
    }

SqlSessionFactory 配置完成后,剩下的就是扫描 mapper 接口并生成代理类存放到 IOC 容器中,这样就可以依赖注入 Mapper 了。

在 Application 启动类中,加上了 @MapperScan(basePackages = {“xxx”}) 注解, MapperScan 注解类上加上另一个注解 @import(MapperScannerRegistrar.class),spring 监测到 @import 注解时会加载其指定的配置类 MapperScannerRegistrar

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@documented
@import(MapperScannerRegistrar.class)
@Repeatable(MapperScans.class)
public @interface MapperScan {
}

2.5、查看 MapperScannerRegistrar 发现,其实现了 importBeanDefinitionRegistrar 接口,该接口的作用是 spring 会调用实现该接口的 registerBeanDefinitions 方法,传入 Annotationmetadata 和BeanDefinitionRegistry 两个参数,Annotationmetadata 的作用是封装了加上@import注解的注解的属性(这里就是MapperScan的basePackages = {“xxx”}),
总结说明:就是 @MapperScan 注解加上了 @import 注解, Annotationmetadata 封装了@MapperScan 注解的 basePackages 属性的值。

2.6、MapperScannerRegistrar 的 registerBeanDefinitions 方法中,获取了 @MapperScan 注解的属性后,调用了自身的重载 registerBeanDefinitions 方法,重载 registerBeanDefinitions 方法通过调用ClassPathMapperScanner 的 doScan 方法就完成了 Mapper 的扫描并生产动态代理加入到 spring 容器中。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5677344.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存