Inyectar mappers

En lugar de codificar DAOs (data access objects) manualmente usando la clase SqlSessionDaoSupport o SqlSessionTemplate, Mybatis-Spring puede crear un mapper thread-safe que puedes inyectar directamente en otros beans.

<bean id="fooService" class="org.mybatis.spring.sample.mapper.FooServiceImpl">
  <property name="userMapper" ref="userMapper" />
</bean>

Una vez inyectado, el mapper está listo para se usado en la lógica de aplicación:

public class FooServiceImpl implements FooService {

  private UserMapper userMapper;

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

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

Observa que no se usa la SqlSession ni ninguna otra referencia a MyBatis en este código. No es necesario ni siquiera crear o cerrar la sesión, MyBatis-Spring se encarga de ello.

Registrar un mapper

La forma de registrar un mapper varía según si quieres usar la configuración XML clásica o la nueva Java Config de Spring 3.0+ (También conocida como @Configuration).

Con confiugración XML

Un mapper se registra en Spring incluyendo un MapperFactoryBean en tu fichero de configuración XML, de la siguiente forma:

<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>

Si el mapper UserMapper tiene un fichero XML de mapeo asociado el MapperFactoryBean lo cargará automáticamente. Por lo tanto no es necesario especificar dicho mapper en el fichero de configuración de MyBatis a no ser que los ficheros XML estén en una lugar distinto del classpath. Ver la sección de SqlSessionFactoryBean y la propiedad configLocation para más información.

El MapperFactoryBean requiere o un SqlSessionFactory o un SqlSessionTemplate. Ambos se pueden informar usando sendas propiedades sqlSessionFactory y sqlSessionTemplate. Si ambas propiedades han sdo informadas la SqlSessionFactory se ignora. Dado que un SqlSessionTemplate debe tener un session factory dicho factory se usará por el MapperFactoryBean.

Con Java Config

Cuando uses Java Config puedes obtener un mapper directamente desde un SqlSessionTemplate como sigue:

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
      SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
      sqlSessionFactory.setDataSource(dataSource());
      return (SqlSessionFactory) sqlSessionFactory.getObject();
    }

    @Bean
    public UserMapper userMapper() throws Exception {
      SqlSessionTemplate sessionTemplate = new SqlSessionTemplate(sqlSessionFactory());
      return sessionTemplate.getMapper(UserMapper.class);
    }

Ten en cuenta que no puedes devolver un mapper obtenido de la una SqlSession normal de MyBatis porque no sería thread safe y solo viviría hasta que la SqlSession que lo creó se cierre. Debes usar un SqlSessionTemplate en su lugar, como se muestra en el ejemplo.

Escanear mappers

No es necesario registrar los mappers uno por uno en el fichero XML de Spring. En lugar de esto, puede dejar que MyBatis-Spring los busque en tu classpath.

Hay tres formas distintas de hacerlo:

  • Usando el elemneto <mybatis:scan/>.
  • Usando la anotación @MapperScan
  • Usando un fichero clásico XML de configuración de Spring y añadiendo el bean MapperScannerConfigurer

Tango <mybatis:scan/> como @MapperScan son características añadidas en MyBatis-Spring 1.2.0. @MapperScan requiere Spring 3.1+.

<mybatis:scan/>

El elemento XML <mybatis:scan/> busca mappers de una forma muy similar a cómo <context:component-scan/> busca beans.

A continuación se muestra un fichero XML de configuración:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
  xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
 
  <mybatis:scan base-package="org.mybatis.spring.sample.mapper" />

</beans>

La propiedad basePackage te permite indicar el paquete base donde residen tus mappers. Puedes indicar más de un paquete usando un punto y coma o una coma como separador. Los mappers serán buscados de forma recursiva comenzando en el/los paquetes especificados.

Fíjate que no es necesario indicar una SqlSessionFactory o SqlSessionTemplate porque el <mybatis:scan/> creará MapperFactoryBeans que pueden ser autowired. Pero si usas más de un DataSource el autowire puede que no te funcione. En este caso puedes usar las propiedades factory-ref or template-ref para indicar los beans correctos a utilizar.

<mybatis:scan/> soporta el filtrado de mappers mediante una interfaz marcador o una anotación. La propiedad annotation especifica la anotación que se debe buscar. La propiedad marker-interface especifica la interfaz a buscar. Si se indican ambas se añadirán todos los mappers que cumplan cualquier criterio. Por defecto ambas propiedades son null asi que todos los interfaces de los paquetes base serán cargados como mappers.

Los mappers descubiertos serán nombrados usando la estratégia de nombres por defecto de Spring para los componentes autodetectados (ver la sección 3.14.4 del manual de Spring). Es decir, si no se encuentra ninguna anotación, se usará el nombre no cualificado sin capitalizar del mapper. Pero si se encuentra una anotación @Component o JSR-330 @Named se obtendrá el nombre de dicha anotación. Fíjate que puedes usar como valor de la annotation el valor org.springframework.stereotype.Component, javax.inject.Named (if you have JSE 6) o una anotación propia (que debe ser a su vez anotada) de forma que la anotación hará las veces de localizador y de proveedor de nombre.

NOTE <context:component-scan/> no puede encontrar y registrar mappers. Los mappers son interfaces y, para poderlos registrar en Spring, el scanner deben conocer cómo crear un MapperFactoryBean para cada interfaz encontrado.

@MapperScan

Si usas la Java Configuration de Spring (@Configuration) posiblemente prefieras usar @MapperScan en lugar de <mybatis:scan/>.

La anotación @MapperScan se usa de la siguiente forma:

@Configuration
@MapperScan("org.mybatis.spring.sample.mapper")
public class AppConfig {

  @Bean
  public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder().addScript("schema.sql").build()
  }

  @Bean
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
    sessionFactory.setDataSource(dataSource());
    return sessionFactory.getObject();
  }
}

La anotación fucniona exactamente igual que <mybatis:scan/> que hemos visto en la sección anterior. También te permite especificar un interfaz marcador o una anotación mediante sus propiedades markerInterface y annotationClass. Tambien puedes indicar una SqlSessionFactory o un SqlSessionTemplate específicos mediante las propiedades sqlSessionFactory y sqlSessionTemplate.

MapperScannerConfigurer

MapperScannerConfigurer es un BeanDefinitionRegistryPostProcessor que se puede incluir como un bean normal en el fichero clásico XML de configuración de Spring. Para configurar un MapperScannerConfigurer añade lo siguiente al fichero de configuración de Spring:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>

Si quieres indicar un sqlSessionFactory o un sqlSessionTemplate observa que se requeiren los nombres de los beans y no sus referencias por ello se usa el atributo value en lugar del habitual ref:

<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />