Spring-MyBatis 之 MapperFactoryBean

本文介绍如何在Spring框架中集成MyBatis,利用MapperFactoryBean简化DAO开发,并解析其内部工作原理。

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

在使用mybatis的时候,我们获取dao的方式一般是这样:

SqlSession session=sessionFactory.openSession();  
UserMapper userMapper=session.getMapper(UserMapper.class); 


但在我们在spring的用例中使用mybatis的时候是这样使用的:

UserMapper userMapper=(UserMapper) context.getBean("userMapper");  

为了代替手工使用 SqlSessionDaoSupport 或 SqlSessionTemplate 编写数据访问对象 (DAO)的代码,MyBatis-Spring 提供了一个动态代理的实现:MapperFactoryBean。这个类 可以让你直接注入数据映射器接口到你的 service 层 bean 中。当使用映射器时,你仅仅如调 用你的 DAO 一样调用它们就可以了,但是你不需要编写任何 DAO 实现的代码,因为 MyBatis-Spring 将会为你创建代理。

使用注入的映射器代码,在 MyBatis,Spring 或 MyBatis-Spring 上面不会有直接的依赖。 MapperFactoryBean 创建的代理控制开放和关闭 session,翻译任意的异常到 Spring 的 DataAccessException 异常中。此外,如果需要或参与到一个已经存在活动事务中,代理将 会开启一个新的 Spring 事务。(转自官网)。


数据映射器接口可以按照如下做法加入到 Spring 中:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">    
    <property name="driverClass" value="${jdbc.driverClassName}" />    
    <property name="jdbcUrl" value="${jdbc.url}" />    
    <property name="user" value="${jdbc.username}" />    
    <property name="password" value="${jdbc.password}" />    
    <property name="maxPoolSize" value="${c3p0.pool.size.max}" />    
    <property name="minPoolSize" value="${c3p0.pool.size.min}" />    
    <property name="initialPoolSize" value="${c3p0.pool.size.ini}" />    
    <property name="acquireIncrement" value="${c3p0.pool.size.increment}" />    
</bean>  
  
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">    
    <property name="dataSource" ref="dataSource" />    
</bean>  

<!-- MapperFactoryBean 数据映射器必须为接口 -->  
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

数据映射器接口:

package org.mybatis.spring.sample.mapper;  
  
import org.apache.ibatis.annotations.Param;  
import org.apache.ibatis.annotations.Select;  
import org.mybatis.spring.sample.bean.User;  
  
public interface UserMapper {  
    @Select("SELECT * FROM user WHERE id = #{id}")     
    User getUser(@Param("id") long id);  
}  

MapperFactoryBean 创建的代理类实现了 UserMapper 接口,并且注入到应用程序中。 因为代理创建在运行时环境中(Runtime,译者注) ,那么指定的映射器必须是一个接口,而 不是一个具体的实现类。

你可以直接在 business/service 对象中以和注入任意 Spring bean 的相同方式直接注入映 射器:

@Service
public class FooServiceImpl implements FooService {
  @Autowired  
  private UserMapper userMapper;

  public void setUserMapper(UserMapper userMapper) {
    this.userMapper = userMapper;
  }

  public User doSomeBusinessStuff(String userId) {
    return this.userMapper.getUser(userId);
  }
}

如果 UserMapper 有一个对应的 MyBatis 的 XML 映射器文件, 如果 XML 文件在类路径的 位置和映射器类相同时, 它会被 MapperFactoryBean 自动解析。 没有必要在 MyBatis 配置文 件 中 去 指 定 映 射 器 , 除 非 映 射 器 的 XML 文 件 在 不 同 的 类 路 径 下 。 可 以 参 考 SqlSessionFactoryBean 的 configLocation 属性来获取更多信息。


注意,当 MapperFactoryBean 需要 SqlSessionFactory 或 SqlSessionTemplate 时。 这些可以通过各自的 SqlSessionFactory 或 SqlSessionTemplate 属性来设置, 或者可以由 Spring 来自动装配。如果两个属性都设置了,那么 SqlSessionFactory 就会被忽略,因为 SqlSessionTemplate 是需要有一个 session 工厂的设置; 那个工厂会由 MapperFactoryBean. 来使用。

MapperFactoryBean继承了SqlSessionDaoSupport,SqlSessionDaoSupport继承DaoSupport,DaoSupport实现了InitializingBean接口

public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {  
    // Let abstract subclasses check their configuration.  
    checkDaoConfig();  
    // Let concrete implementations initialize themselves.  
    try {  
     //initDao()方法是模板方法,设计为留给子类做进一步逻辑处理。
        initDao();  
    }  
    catch (Exception ex) {  
        throw new BeanInitializationException("Initialization of DAO failed", ex);  
    }  
}  
该方法主要包含两个功能,一个是调用checkDaoConfig()方法,一个是调用initDao方法。checkDaoConfig方法在DaoSupport是抽象方法

@Override  
 protected void checkDaoConfig() {  
   super.checkDaoConfig();  
   notNull(this.mapperInterface, "Property 'mapperInterface' is required");  
   Configuration configuration = getSqlSession().getConfiguration();  
   if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {  
     try {  
       configuration.addMapper(this.mapperInterface);  
     } catch (Throwable t) {  
       logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", t);  
       throw new IllegalArgumentException(t);  
     } finally {  
       ErrorContext.instance().reset();  
     }  
   }  
 }  

该方法主要是检查dao的配置,主要是检验sqlSessionFactory和mapperInterface属性不能为空,以及检测接口对于的映射文件是否存在,如果存在,那么就把它添加到configuration里面去,注册mapper。


在上面的函数中,configuration.addMapper(this.mapperInterface)其实就是将PersonDao注册到映射类型中,如果你可以保证这个接口一定存在对应的映射文件,那么其实这个验证并没有必要。但是,由于这个是我们自行决定的配置,无法保证这里配置的接口一定存在对应的映射文件,所以这里非常有必要进行验证。在执行此代码的时候,MyBatis会检查嵌入的映射接口是否存在对应的映射文件,如果没有回抛出异常,Spring正是在用这种方式来完成接口对应的映射文件存在性验证。


获取MapperFactoryBean的实例

public T getObject() throws Exception {  
  return getSqlSession().getMapper(this.mapperInterface);  
} 
在这里封装了getMapper操作,返回接口的实例。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值