<?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 | Mapper をインジェクト（注入）する</title>
    <author email="hpresnall@gmail.com">Hunter Presnall</author>
    <author email="eduardo.macarron@gmail.com">Eduardo Macarron</author>
    <author email="harawata@gmail.com">Iwao AVE!</author>    
  </properties>

  <body>
    <section name="Mapper の注入">
      <p>
        MyBatis-Spring がスレッドセーフな Mapper を生成してくれるので、<code>SqlSessionDaoSupport</code> や <code>SqlSessionTemplate</code> を使って手動で DAO オブジェクトを生成するコードは不要となります。
        生成された Mapper は他の Bean に注入することができます。
      </p>

      <source><![CDATA[<bean id="fooService" class="org.mybatis.spring.sample.service.FooServiceImpl">
  <constructor-arg ref="userMapper" />
</bean>]]></source>
 
      <p>
        アプリケーション側の処理では、注入された Mapper のメソッドを呼び出すだけです。
      </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>
        このコードには <code>SqlSession</code> や MyBatis への参照が含まれていない点に注目してください。
        また、セッションの生成やオープン、クローズも MyBatis-Spring が処理してくれるため不要となります。
       </p>

	<subsection name="Mapper の登録" id="register">
	  <p>
	    Mapper を Bean として登録する方法は、Spring の設定を XML ファイルを使って行う場合と Spring 3.0 以降で導入された Java Config (= @Configuration) を使う場合で異なります。</p>
	
      <h4>XML で設定する場合</h4>
      
      <p>
        XML ファイルを使って Spring を設定する場合、次のように <code>MapperFactoryBean</code> のエントリーを追加することで Mapper を Spring Bean として登録することができます。
      </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>
        ここで指定した UserMapper のインターフェイスと同じクラスパスに MyBatis の XML Mapper ファイルが配置されている場合は自動的にロードされます。
        XML Mapper が異なるクラスパスに配置されている場合を除けば、MyBatis の設定ファイルでこの Mapper を指定する必要はありません。
        詳しくは <code>SqlSessionFactoryBean</code> の <code><a href="factorybean.html">configLocation</a></code> プロパティの説明を参照してください。
      </p>

      <p>
        <code>MapperFactoryBean</code> を登録する際は <code>SqlSessionFactory</code> あるいは <code>SqlSessionTemplate</code> のどちらかを指定する必要があります。
        指定対象のプロパティは、それぞれ <code>sqlSessionFactory</code> と <code>sqlSessionTemplate</code> です。
        両方が指定された場合、 <code>SqlSessionFactory</code> の指定は無視され、<code>SqlSessionTemplate</code> の登録時に指定した Session Factory が使われます。
      </p>
      
       <h4>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="Mapper の自動検出" id="scan">
      <p>
        上で説明した方法では Mapper を個別に指定していましたが、MyBatis-Spring では特定のクラスパスに含まれる Mapper を自動検出させることもできます。     
      </p>
      
      <p>
        これには３通りの方法があります。
      </p>
      <ul>
        <li><code>&lt;mybatis:scan/&gt;</code> 要素を使う。</li>
        <li><code>@MapperScan</code> アノテーションを使う。</li>
        <li>Spring の XML 設定ファイルに <code>MapperScannerConfigurer</code> のエントリーを追加する。</li>
      </ul>
      
      <p><code>&lt;mybatis:scan/&gt;</code> または <code>@MapperScan</code> を使う場合は MyBatis-Spring 1.2.0 以降が必要です。また <code>@MapperScan</code> を使う場合は Spring 3.1 以降が必要となります。</p>

      <p>
        2.0.2以降では、Mapperの自動検出機能は、Mapper Beanの遅延初期化の有効/無効を制御するオプション（<code>lazy-initialization</code>）をサポートします。
        このオプションを追加する動機は、Spring Boot 2.2でサポートされた遅延初期化を制御する機能をサポートすることです。
        このオプションのデフォルトは<code>false</code>です（遅延初期化を使用しません）。
        開発者がMapper Beanを遅延初期化したい場合は、明示的にこのオプションを<code>true</code>に設定する必要があります。
      </p>
      <p>
        <span class="label important">重要</span> 遅延初期化機能を使用する場合は、開発者は以下の制限を理解しておく必要があります。
        以下の条件のいずれかに一致する場合、通常あなたのアプリケーションで遅延初期化機能を使用することはできません。
      </p>
      <ul>
        <li><code><![CDATA[<association>]]></code>(<code>@One</code>) and <code><![CDATA[<collection>]]></code>(<code>@Many</code>)を利用して、<b>他のMapperの</b>ステートメントを参照している場合</li>
        <li><code><![CDATA[<include>]]></code>を利用して、<b>他のMapperの</b>フラグメントをインクルードしている場合</li>
        <li><code><![CDATA[<cache-ref>]]></code>(<code>@CacheNamespaceRef</code>)を利用して、<b>他のMapperの</b>キャッシュを参照している場合</li>
        <li><code><![CDATA[<select resultMap="...">]]></code>(<code>@ResultMap</code>)を利用して、<b>他のMapperの</b>結果マッピングを参照している場合</li>
      </ul>

      <p>
        <span class="label important">NOTE</span> しかしながら、以下のように<code>@DependsOn</code>(Springの機能)を利用して、
        依存するMapper Beanも同時に初期化すると遅延初期化機能を利用することができるようになります。
      </p>

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

      <h4>&lt;mybatis:scan/&gt;</h4>
      
      <p>
        <code>&lt;mybatis:scan/&gt;</code> は、Spring の <code>&lt;context:component-scan/&gt;</code> が Bean を検索するのと良く似た方法で Mapper を検出します。
      </p>
      
      <p>XML 設定の例：</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>
        <code>base-package</code> 属性で Mapper ファイルを含むパッケージを指定します。
        セミコロンまたはカンマ区切りで複数のパッケージを指定することもできます。
        また、指定されたパッケージが内包するパッケージも検索対象となります。
      </p>

      <p>
        ここでは <code>&lt;mybatis:scan/&gt;</code> に <code>SqlSessionFactory</code> や <code>SqlSessionTemplate</code> を指定していませんが、この場合は Autowired 可能な <code>MapperFactoryBean</code> が自動的に生成されます。
        ただし、複数の <code>DataSource</code> を利用する場合は Autowired に頼ることができないので、 <code>factory-ref</code> または <code>template-ref</code> 属性を使って適切な Bean を指定する必要があります。
      </p>

      <p>
        <code>&lt;mybatis:scan/&gt;</code> を使う場合、マーカーインターフェイスまたはアノテーションを指定して Mapper をフィルタリングすることができます。
        検出対象のアノテーションを指定するには <code>annotation</code> 属性を使います。
        検出対象の Mapper が実装するインターフェイスを指定する場合は <code>marker-interface</code> 属性を使います。
        両方の属性が指定された場合、どちらかの条件を満たすインターフェイスが Mapper として登録されます。
        デフォルトではどちらも null となっており、<code>base-package</code> で指定したパッケージに含まれるすべてのインターフェイスが Mapper としてロードされます。
      </p>

      <p>
        検出された Mapper は、Spring の自動検出コンポーネントに対するデフォルト命名規則によって Bean 名が決められます（<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> を参照してください）。
        アノテーションによる指定がない場合はクラス名の先頭を小文字にした文字列が Bean 名となりますが、@Component あるいは JSR-330 の @Named アノテーションを使って Bean 名を明示的に指定することもできます。
        先に説明した <code>annotation</code> 属性で <code>org.springframework.stereotype.Component</code> や <code>javax.inject.Named</code> （Java 6 以降を利用している場合のみ）を指定すれば、検出時のマーカーと Bean 名の指定を１つのアノテーションで兼ねることができます。
        同じ目的で独自に定義したアノテーションを使うこともできますが、このアノテーション自体に @Component か @Named を付加しておく必要があります。
      </p>

      <p>
        <span class="label important">NOTE</span> Spring 標準の <code>&lt;context:component-scan/&gt;</code> を使って Mapper を検出することはできません。
        Mapper はインターフェイスなので、各 Mapper に対する <code>MapperFactoryBean</code> の生成方法が分かっていないと Spring Bean として登録することができないのです。
      </p>

      <h4>@MapperScan</h4>
      
      <p>
        Java Config を使って Spring を設定しているのなら、<code>&lt;mybatis:scan/&gt;</code> よりも <code>@MapperScan</code> を使う方が気に入ると思います。
      </p>
      
      <p><code>@MapperScan</code> アノテーションは次のように使用します。</p>
   
   <source><![CDATA[@Configuration
@MapperScan("org.mybatis.spring.sample.mapper")
public class AppConfig {
  // ...
}
]]></source>
	
	  <p>
    このアノテーションは前章で説明した <code>&lt;mybatis:scan/&gt;</code> と全く同じ要領で Mapper の検出を行います。
    引数 <code>markerInterface</code>, <code>annotationClass</code> を使えば検出対象のマーカーインターフェイスとアノテーションを指定することもできますし、<code>sqlSessionFactory</code>, <code>sqlSessionTemplate</code> で <code>SqlSessionFactory</code> や <code>SqlSessionTemplate</code> を指定することができます。
	  </p>
     
      <h4>MapperScannerConfigurer</h4>
        
      <p>
        <code>MapperScannerConfigurer</code> は <code>BeanDefinitionRegistryPostProcessor</code> として定義されているので、従来の XML による設定で通常の Bean として登録することができます。
        <code>MapperScannerConfigurer</code> の登録は次のように行います。
      </p>
        <source><![CDATA[<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>]]></source>

      <p>
        特定の <code>sqlSessionFactory</code> または <code>sqlSessionTemplate</code> を指定する場合は、 Bean を参照ではなく <strong>名前で</strong> 指定する必要があるので、<code>ref</code> ではなく <code>value</code> を使います。
      </p>
      <source><![CDATA[<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />]]></source>
    
      <p>
        <span class="label important">NOTE</span> MyBatis-Spring 1.0.2 までは有効なプロパティは <code>sqlSessionFactoryBean</code> と <code>sqlSessionTemplateBean</code> のみでしたが、 <code>MapperScannerConfigurer</code> が <code>PropertyPlaceholderConfigurer</code> よりも先に読み込まれるためエラーの原因となっていました。
        この問題を回避するため、これらのプロパティの使用は非推奨となり、新たに追加された <code>sqlSessionFactoryBeanName</code> と <code>sqlSessionTemplateBeanName</code> を使うことが推奨されています。
      </p>
      </subsection>
    </section>
  </body>
</document>
