mybatis-spring:SqlSessionFactoryBean

本文深入探讨了在SpringBoot项目中整合MyBatis的过程,详细解析了SqlSessionFactoryBean、MapperFactoryBean及SqlSessionTemplate的角色与工作原理,揭示了DAO层接口如何通过代理模式与数据库交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言

demo: springboot+mybatis的MybatisConfig中有这样两个bean配置(事务此时不看):

    // 数据源配置
    @Bean
    public DataSource dataSource() {
        // mybatis自带的一个简易数据库连接池,只是为了debug代码,这个就不关心了
        PooledDataSource pooledDataSource = new PooledDataSource();
        pooledDataSource.setDriver(environment.getProperty("mysql.driver"));
        pooledDataSource.setUsername(environment.getProperty("mysql.username"));
        pooledDataSource.setPassword(environment.getProperty("mysql.passwd"));
        pooledDataSource.setUrl(environment.getProperty("mysql.url"));
        return pooledDataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws IOException {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath:/mapper/*.xml"));
        return sqlSessionFactoryBean;
    }

dataSource数据源配置的bean,是通过依赖注入传递给SqlSessionFactoryBean这个bean了。

问题点在于SqlSessionFactoryBean在整个容器初始化过程中起了什么作用。

@MappserScan

mybatis-spring:@MapperScan注解中解释使用这个注解,完成两件事:

                  1. 扫描指定接口

                  2. 注册这些接口的bean定义到spring容器(实际是FactoryBean定义)

然后spring容器在对Dao层接口注入的时候,实际注入的是一个Mybatis创建的代理对象:MapperProxy,

public class MapperProxy<T> implements InvocationHandler, Serializable {

  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }
}

看构造方法和属性字段,mapperInterface是被代理的接口,methodCache是接口的方法,另外一个关键属性是sqlSession。

SqlSession是MyBatis 的一个主要 Java 接口。通过它的实现可以执行SQL命令、执行事务等。所以它是执行SQL的关键。现在需要确认的是SqlSession与SqlSessionFactoryBean的关系。

SqlSessionFactoryBean

见名知义,SqlSessionFactoryBean是创建SqlSessionFactory的:

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {}

它也实现了FactoryBean,并且实现了InitializingBean接口的afterPropertiesSet()方法。这样在spring容器实例化这个bean的时候,便会回调afterPropertiesSet()方法:

  @Override
  public void afterPropertiesSet() throws Exception {
    notNull(dataSource, "Property 'dataSource' is required");
    notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");

    this.sqlSessionFactory = buildSqlSessionFactory();
  }

来创建SqlSessionFactory实例,然后看下它对FactoryBean的接口方法实现:

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

    return this.sqlSessionFactory;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Class<? extends SqlSessionFactory> getObjectType() {
    return this.sqlSessionFactory == null ? SqlSessionFactory.class : this.sqlSessionFactory.getClass();
  }

spring容器中某个bean的字段需要依赖注入SqlSessionFactory实例的时候,会调用getObject方法,返回SqlSessionFactory实例。

那么哪个bean的属性需要注入SqlSessionFactory?答案是:MapperFactoryBean。

上文说扫描到的每个接口注册的工厂bean定义的就是MapperFactoryBean这个bean定义。

它的用处就是注入service的dao层接口属性(如在ServiceImpl的属性UserDao)的代理对象的时候,会返回这个MapperProxy代理对象。mybatis-spring:@MapperScan注解文中有提到解释。

问题来了,这里注入的是SqlSessionFactory对象,MapperProxy需要的是SqlSession实现类。答案看下面:

MapperFactoryBean继承自SqlSessionDaoSupport:

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

在父类SqlSessionDaoSupport里有方法:

  public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
    if (!this.externalSqlSession) {
      this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
    }
  }

而SqlSessionTemplate是SqlSession的实现:

public class SqlSessionTemplate implements SqlSession, DisposableBean {

  private final SqlSessionFactory sqlSessionFactory;

  private final ExecutorType executorType;

  private final SqlSession sqlSessionProxy;

  private final PersistenceExceptionTranslator exceptionTranslator;
}

而它的sqlSessionProxy实例是从它的构造方法里构造的:

  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;
    this.sqlSessionProxy = (SqlSession) newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class },
        new SqlSessionInterceptor());
  }

所以MapperProxy的SqlSession实例,实际是SqlSessionTemplate实例,下层再委托给sqlSessionProxy代理对象进行实际调用。

因此,注入ServiceImpl的UserDao属性字段时,发生以下过程:

1. spring容器注入UserDao属性的MapperProxy实例时,依赖MapperProxy实例

2. 此时实例MapperFactoryBean来创建MapperProxy实例

3. 创建MapperFactoryBean需要依赖注入SqlSessionFacotry实例

4. 使用SqlSessionFactoryBean来创建SqlSessionFactory实例

最终完成整个过程,注入userDao属性的值 MapperProxy实例。

 

 

配置MyBatis的配置类主要是通过在配置文件中进行相关的配置来实现。在Spring Boot中,可以通过在application.yml或application.properties文件中进行配置来实现。 下面是一个示例的配置类: ``` @Configuration @MapperScan("zchao.com.springboot.generator.mapper") public class MyBatisConfig { @Autowired private DataSource dataSource; @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); // 设置MyBatis配置文件的位置 sessionFactory.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis-config.xml")); // 设置Mapper文件的位置 sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml")); return sessionFactory.getObject(); } } ``` 在以上示例中,`@MapperScan`注解用于指定MyBatis的Mapper接口所在的包路径。`SqlSessionFactory` bean用于创建`SqlSession`实例,`SqlSessionFactoryBean`类用于配置SqlSessionFactory的相关属性,如数据源、MyBatis的配置文件位置、Mapper文件的位置等。 需要注意的是,以上示例中的数据源配置可以根据实际情况进行修改,比如使用Druid连接池等。另外,需要将相关的依赖添加到pom.xml文件中,如`mybatis-spring-boot-starter`和`druid`等。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [springboot配置mybatis](https://blog.youkuaiyun.com/weixin_52831324/article/details/129212839)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不识君的荒漠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值