SpringBoot整合Mybatis及自动装配源码分析

本文主要内容:

1.  SpringBoot整合MyBatis主要步骤;

2. SpringBoot自动装配MyBatis源码分析;

1.  SpringBoot整合MyBatis主要步骤

1. 引入数据库驱动(mysql为例)

<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
</dependency>

2. 引入Mybatis starter 

<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>1.3.2</version>
</dependency>

3. 增加数据源配置(Druid连接池可参考 Spring Boot数据源相关

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql:///test_mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    initialization-mode: always
    hikari:
      connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci
      connection-timeout: 30000       # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒
      minimum-idle: 5                 # 最小连接数
      maximum-pool-size: 20           # 最大连接数
      auto-commit: true               # 自动提交
      idle-timeout: 600000            # 连接超时的最大时长(毫秒),超时则被释放(retired),默认:10分钟
      pool-name: DateSourceHikariCP     # 连接池名字
      max-lifetime: 500000           # 连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认:30分钟 1800000ms
      connection-test-query: SELECT 1

4.  增加实体类 及 Mapper接口

public class User {
   private Integer id;
   private String username;
   private String password;
   private String birthday;
   ...... setter  getter ......
}
public interface UserMapper {

   @Select("select * from user")
   List<User> findAll();
}

5. 启动类中增加Mapper接口扫描

@MapperScan(basePackages="com.kay.mapper") // com.kay.mapper根据自己项目自己修改

2. SpringBoot自动装配MyBatis源码分析 

 1. @MapperScan注解 本质是将MapperScannerRegistrar导入到容器中,在MapperScannerRegistrar中实现了ImportBeanDefinitionRegistrar接口类及registerBeanDefinitions方法,该方法将在spring实例化之前,调用invokeBeanFactoryPostProcessors 时被调用;

@Import({MapperScannerRegistrar.class})
public @interface MapperScan {

断点 MapperScannerRegistrar 下的 registerBeanDefinitions()方法,观看其调用栈可以验证其调用时机;

在 registerBeanDefinitions中,将

A. 调用doScan(),将指定包下basePackages下所有类信息,封装成BeanDefinition对象存档在IOC容器中,即beanDefinitionMap中;

B.调用processBeanDefinitions(),将mapper接口(GenericBeanDefinition)的beanClass属性为MapperFactoryBean类型并加入到spring的bean容器中;而MapperFactoryBean 实现了FactoryBean; 当后期spring实例化bean容器中对象时,针对于Mapper接口对应的BeanDefinition对象,将调用MapperFactoryBean的getBean()方法;返回 代理对象

public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    ....

    public T getObject() throws Exception {
        return this.getSqlSession().getMapper(this.mapperInterface);
    }
    ......
}

 2. 在mybatis-spring-boot-autoconfigure jar的META-INF/spring.factories中定义了
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration

@org.springframework.context.annotation.Configuration
@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class })
@ConditionalOnBean(DataSource.class)
@EnableConfigurationProperties(MybatisProperties.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration {

    ....

  @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()));
    }
    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);
    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 (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
      factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
    }
    if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
      factory.setMapperLocations(this.properties.resolveMapperLocations());
    }

    return factory.getObject();
  }

  @Bean
  @ConditionalOnMissingBean
  public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
    ExecutorType executorType = this.properties.getExecutorType();
    if (executorType != null) {
      return new SqlSessionTemplate(sqlSessionFactory, executorType);
    } else {
      return new SqlSessionTemplate(sqlSessionFactory);
    }
  }

此配置类MybatisAutoConfiguration将在容器调用BeanFactory的后置处理器invokeBeanFactoryPostProcessors时获取到类信息,封装成BeanDefinition对象存放到IOC容器beanDefinitionMap中,在finishBeanFactoryInitialization实例化对象时生成其注入的bean对象SqlSessionFactory  及 SqlSessionTemplate   对象;

在生成 SqlSessionFactory   时:在getObject()方法中, 将封装Configuration对象,最终调用this.sqlSessionFactoryBuilder.build(configuration)实例化SqlSessionFactory对象

    public SqlSessionFactory getObject() throws Exception {
        if (this.sqlSessionFactory == null) {
            this.afterPropertiesSet();
        }

        return this.sqlSessionFactory;
    }
    
    public void afterPropertiesSet() throws Exception {
        .....
        
        this.sqlSessionFactory = this.buildSqlSessionFactory();
    }

    protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
        XMLConfigBuilder xmlConfigBuilder = null;
        Configuration configuration;
        
        ........
        
        return this.sqlSessionFactoryBuilder.build(configuration);
    }

 在生成 SqlSessionTemplate   中:封装了SqlSession对象

public class SqlSessionTemplate implements SqlSession, DisposableBean {
    private final SqlSessionFactory sqlSessionFactory;
    private final ExecutorType executorType;
    private final SqlSession sqlSessionProxy;
    private final PersistenceExceptionTranslator exceptionTranslator;

    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
    }

    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
        this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), true));
    }

    public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
        Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
        Assert.notNull(executorType, "Property 'executorType' is required");
        this.sqlSessionFactory = sqlSessionFactory;
        this.executorType = executorType;
        this.exceptionTranslator = exceptionTranslator;
        this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
    }
    .......
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值