<?xml version="1.0" encoding="UTF-8"?>
<!--

    Copyright ${license.git.copyrightYears} the original author or authors.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

-->
<document xmlns="http://maven.apache.org/XDOC/2.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">

  <properties>
    <title>MyBatis-Spring | Inyectar mappers</title>
    <author email="hpresnall@gmail.com">Hunter Presnall</author>
    <author email="eduardo.macarron@gmail.com">Eduardo Macarron</author>
  </properties>

  <body>
    <section name="Inyectar mappers">
      <p>
        En lugar de codificar DAOs (data access objects) manualmente usando la clase
        <code>SqlSessionDaoSupport</code> o <code>SqlSessionTemplate</code>, Mybatis-Spring 
		puede crear un mapper thread-safe que puedes inyectar directamente en otros beans.
      </p>

      <source><![CDATA[<bean id="fooService" class="org.mybatis.spring.sample.service.FooServiceImpl">
  <constructor-arg ref="userMapper" />
</bean>]]></source>

      <p>
         Una vez inyectado, el mapper está listo para se usado en la lógica de aplicación:
      </p>
         <source><![CDATA[public class FooServiceImpl implements FooService {

  private final UserMapper userMapper;

  public FooServiceImpl(UserMapper userMapper) {
    this.userMapper = userMapper;
  }

  public User doSomeBusinessStuff(String userId) {
    return this.userMapper.getUser(userId);
  }
}]]></source>
       <p>
         Observa que no se usa la <code>SqlSession</code> 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.
       </p>

	<subsection name="Registrar un mapper" id="register">

	  <p>
	    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).</p>
	
      <h4>Con confiugración XML</h4>
      
      <p>
        Un mapper se registra en Spring incluyendo un <code>MapperFactoryBean</code> en tu fichero de configuración XML, de la siguiente forma:
      </p>
        <source><![CDATA[<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>]]></source>
   
      <p>
        Si el mapper UserMapper tiene un fichero XML de mapeo asociado el <code>MapperFactoryBean</code> 
        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 <code>SqlSessionFactoryBean</code> y la propiedad
        <code><a href="factorybean.html">configLocation</a></code>
        para más información.
      </p>

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

    <source><![CDATA[
@Bean
public MapperFactoryBean<UserMapper> userMapper() throws Exception {
  MapperFactoryBean<UserMapper> factoryBean = new MapperFactoryBean<>(UserMapper.class);
  factoryBean.setSqlSessionFactory(sqlSessionFactory());
  return factoryBean;
}]]></source>

    </subsection>

    <subsection name="Escanear mappers" id="scan">
      <p>
        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.
      </p>
      
      <p>
        Hay tres formas distintas de hacerlo:
      </p>
      <ul>
        <li>Usando el elemneto <code>&lt;mybatis:scan/&gt;</code>.</li>
        <li>Usando la anotación <code>@MapperScan</code></li>
        <li>Usando un fichero clásico XML de configuración de Spring y añadiendo el bean <code>MapperScannerConfigurer</code></li>
      </ul>
      
      <p>Tango <code>&lt;mybatis:scan/&gt;</code> como <code>@MapperScan</code> son características añadidas en MyBatis-Spring 1.2.0.
      <code>@MapperScan</code> requiere Spring 3.1+.</p>

      <p>
        Since 2.0.2, mapper scanning feature support a option (<code>lazy-initialization</code>)
        that control lazy initialization enabled/disabled of mapper bean.
        The motivation for adding this option is supporting a lazy initialization control feature supported by Spring Boot 2.2.
        The default of this option is <code>false</code> (= not use lazy initialization).
        If developer want to use lazy initialization for mapper bean, it should be set to the <code>true</code> expressly.
      </p>
      <p>
        <span class="label important">IMPORTANT</span> If use the lazy initialization feature,
        the developer need to understand following limitations. If any of following conditions are matches,
        usually the lazy initialization feature cannot use on your application.
      </p>
      <ul>
        <li>When refers to the statement of <b>other mapper</b> using <code><![CDATA[<association>]]></code>(<code>@One</code>) and <code><![CDATA[<collection>]]></code>(<code>@Many</code>)</li>
        <li>When includes to the fragment of <b>other mapper</b> using <code><![CDATA[<include>]]></code></li>
        <li>When refers to the cache of <b>other mapper</b> using <code><![CDATA[<cache-ref>]]></code>(<code>@CacheNamespaceRef</code>)</li>
        <li>When refers to the result mapping of <b>other mapper</b> using <code><![CDATA[<select resultMap="...">]]></code>(<code>@ResultMap</code>)</li>
      </ul>

      <p>
        <span class="label important">NOTE</span> However, It become possible to use it by simultaneously initializing dependent beans using <code>@DependsOn</code>(Spring's feature) as follow:
      </p>

      <source><![CDATA[@DependsOn("vendorMapper")
public interface GoodsMapper {
  // ...
}]]></source>

      <h4>&lt;mybatis:scan/&gt;</h4>
      
      <p>
        El elemento XML <code>&lt;mybatis:scan/&gt;</code> busca mappers de una forma muy similar a cómo
        <code>&lt;context:component-scan/&gt;</code> busca beans.
      </p>
      
      <p>A continuación se muestra un fichero XML de configuración:</p>

        <source><![CDATA[<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.xsd
  http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
 
  <mybatis:scan base-package="org.mybatis.spring.sample.mapper" />

  <!-- ... -->

</beans>]]></source>

      <p>
        La propiedad <code>basePackage</code> 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.
      </p>

      <p>
        Fíjate que no es necesario indicar una <code>SqlSessionFactory</code> o
        <code>SqlSessionTemplate</code> porque el <code>&lt;mybatis:scan/&gt;</code>
        creará <code>MapperFactoryBean</code>s que pueden ser autowired. Pero si usas más de un <code>DataSource</code> 
        el autowire puede que no te funcione. En este caso puedes usar las propiedades <code>factory-ref</code> or
        <code>template-ref</code> para indicar los beans correctos a utilizar.
      </p>
   
      <p>
        <code>&lt;mybatis:scan/&gt;</code> soporta el filtrado de mappers mediante una interfaz marcador o una anotación.
        La propiedad <code>annotation</code> especifica la anotación que se debe buscar.
        La propiedad <code>marker-interface</code> especifica la interfaz a buscar. 
        Si se indican ambas se añadirán todos los mappers que cumplan <strong>cualquier</strong> criterio.
        Por defecto ambas propiedades son null asi que todos los interfaces de los paquetes base serán cargados como mappers.
      </p>

      <p>
        Los mappers descubiertos serán nombrados usando la estratégia de nombres por defecto de Spring para los componentes
        autodetectados (see <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-scanning-name-generator">the Spring reference document(Core Technologies -Naming autodetected components-)</a>).
        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 <code>annotation</code> el valor <code>org.springframework.stereotype.Component</code>,
        <code>javax.inject.Named</code> (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.
      </p>

      <p>
        <span class="label important">NOTE</span> <code>&lt;context:component-scan/&gt;</code> 
        no puede encontrar y registrar mappers. Los mappers son interfaces y, para poderlos registrar en Spring,
        el scanner deben conocer cómo crear un <code>MapperFactoryBean</code> para cada interfaz encontrado.
      </p>

      <h4>@MapperScan</h4>
      
      <p>
        Si usas la Java Configuration de Spring (@Configuration) posiblemente prefieras usar 
        <code>@MapperScan</code> en lugar de <code>&lt;mybatis:scan/&gt;</code>.  
      </p>
      
      <p>La anotación <code>@MapperScan</code> se usa de la siguiente forma:</p>
   
   <source><![CDATA[@Configuration
@MapperScan("org.mybatis.spring.sample.mapper")
public class AppConfig {
  // ...
}
]]></source>
	
	  <p>
	   La anotación fucniona exactamente igual que <code>&lt;mybatis:scan/&gt;</code> que hemos visto en la sección anterior.
	   También te permite especificar un interfaz marcador o una anotación mediante sus propiedades 
	   <code>markerInterface</code> y <code>annotationClass</code>. 
	   Tambien puedes indicar una <code>SqlSessionFactory</code> o un <code>SqlSessionTemplate</code> específicos
	   mediante las propiedades <code>sqlSessionFactory</code> y <code>sqlSessionTemplate</code>.
	  </p>
     
      <h4>MapperScannerConfigurer</h4>
        
      <p>
        <code>MapperScannerConfigurer</code> es un <code>BeanDefinitionRegistryPostProcessor</code> 
        que se puede incluir como un bean normal en el fichero clásico XML de configuración de Spring.
        Para configurar un <code>MapperScannerConfigurer</code> añade lo siguiente al fichero de configuración de Spring:
      </p>
        <source><![CDATA[<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>]]></source>

      <p>
        Si quieres indicar un <code>sqlSessionFactory</code> o un <code>sqlSessionTemplate</code>
        observa que se requeiren <strong>los nombres de los beans</strong> y no sus referencias
        por ello se usa el atributo <code>value</code> en lugar del habitual <code>ref</code>:
      </p>
      <source><![CDATA[<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />]]></source>
    
      </subsection>
    </section>
  </body>
</document>
