SQL内のXMLファイルMyBatisのでDAOインターフェイスは、関係を確立することですどのように?

テキストの先頭の前に、最初のSQLでのダオ・インターフェースおよびXML文書が一から一である方法を説明しますか?

文を終了する。MyBatisの最初のネームスペース(名前空間)内のxmlファイルを介して、DAOでビルド関係をXMLファイルを解析し、次にXML SQL各セクションでDAOインターフェイスに関連付けてIDを有することになります。

そこで質問です:「私は競合ではありません、このDAO関係に関連している2つのXMLファイルを使用している場合は?」

この質問で、私たちは、次のトピックを開始したいです!

まず、初期化

私たちは、各MyBatisのベースのアプリケーションは、SqlSessionFactoryのインスタンスに基づいています知っている必要がまず第一には、SqlSessionFactory例がSqlSessionFactoryBuilderすることによって得ることができる、センタリング。

しかし、SqlSessionFactoryインタフェース、実際にはその二つの方法があります:openSessiongetConfiguration

前記openSession方法は、SQLSESSIONオブジェクト・データベースは、必要な機能を完了CRUD得ることです。しかし、SqlSessionFactory属性少なすぎる、する必要があるgetConfigurationマッパーマッピングファイル、SQLパラメーター、戻り値の型、キャッシュやその他の属性を設定するには、フィット。

/**
 * Creates an {@link SqlSession} out of a connection or a DataSource
 * 
 * @author Clinton Begin
 */
public interface SqlSessionFactory {

  SqlSession openSession();

  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}复制代码

設定getConfigurationクラスに属するメソッドを参照してください。あなたは家政婦としてそれを設定することができます。すべてのMyBatisの構成情報は、Configurationオブジェクトに保持され、基本的にすべてのオブジェクトは、それへの参照を保持します。

春はプロセスをインスタンス化するようMyBatisのは、春と一緒に使用します。しかし、私たちは日々発展しています。

私たちが見ているかもしれだからorg.mybatis.spring.SqlSessionFactoryBean、それはInitializingBeanインタフェースを実装しています。これが示すように、このクラスはafterPropertiesSetへの呼び出しをインスタンス化された後に()。それは唯一の方法であります

public void afterPropertiesSet() throws Exception {
    this.sqlSessionFactory = buildSqlSessionFactory();
}复制代码

そして、これはafterPropertiesSetある1つのアクションだけ、ですbuildSqlSessionFactoryこれは、2つの部分の外観に分けることができます。

  • 図1に示すように、プロパティ属性ローディング・コンフィギュレーション・ファイルの様々な構成要素、構成に設定を解析
  • 2、ロード・マッパーファイルは、MappedStatementにパッケージ化SQL文は、構成に配置されたオブジェクトを解析します。

二、マッパーインタフェースメソッドが呼び出される方法ですか?

大きく二つの方法があります。

  • MyBatisの提供API

使用API​​ MyBatisのはSQLSESSIONオブジェクトを取得することで、操作によって提供され、その文Id及びパラメータに従ってデータベースを操作します。

String statement = "com.mmzsblog.business.dao.MemberMapper.getMemberList";
List<Member> result = sqlsession.selectList(statement);复制代码

  • マッパーインタフェース

マッパーは、インターフェイスは、サービスデータおよびその中の動作方法のセットを定義する定義しました。注入層マッパーサービスプロパティ、データベース操作を実行するために呼び出すことができる方法です。このような

public interface MemberMapper {    
    List<Member> getMemberList();
}

@Service
public class MemberServiceImpl implements MemberService{
    @Resource
    private MemberMapper memberMapper;
    
    @Override
    public List<Member> getMemberList() {
        return memberMapper.getMemberList();
    }
}复制代码

だから、MemberMapperちょうどインタフェース、および何の実装クラスはありません。私たちは、SQL文の最終的な実行を行うには、それがどのように、それを呼び出すときは?

三、Mapperプロキシインタフェースの作成プロセス

3.1まず、スキャンする基本的なパッケージパスを設定します

コンフィギュレーションの注釈の方法で:

@MapperScan({"com.mmzsblog.business.dao"})复制代码

XML設定や方法:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.mmzsblog.business.dao" />
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>复制代码

3.2スタートスキャン

私たちは、に来てorg.mybatis.spring.mapper.MapperScannerConfigurer、このクラス、あなたはそれがいくつかのインタフェースを実装して見ることができます。

どこにフォーカスがありますBeanDefinitionRegistryPostProcessorそれは、メソッドをビーンの登録情報を動的にすることができますpostProcessBeanDefinitionRegistry()

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (this.processPropertyPlaceHolders) {
            this.processPropertyPlaceHolders();
        }
        
        // 创建ClassPath扫描器,设置属性,然后调用扫描方法
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.setAddToConfig(this.addToConfig);
        scanner.setAnnotationClass(this.annotationClass);
        scanner.setMarkerInterface(this.markerInterface);
        scanner.setSqlSessionFactory(this.sqlSessionFactory);
        scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
        scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
        scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
        scanner.setResourceLoader(this.applicationContext);
        scanner.setBeanNameGenerator(this.nameGenerator);
        // 创建ClassPath扫描器,设置属性,然后调用扫描方法
        scanner.registerFilters();
        scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
    }复制代码

ClassPathMapperScanner春はクラスから継承されClassPathBeanDefinitionScanner、それが親クラスへのスキャンメソッドの呼び出しですので、ClassPathBeanDefinitionScannerスキャン方法、

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
    ……
    public int scan(String... basePackages) {
        // 
        int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
        this.doScan(basePackages);
        if (this.includeAnnotationConfig) {
            AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
        }

        return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
    }
    ……
}    复制代码

親クラスとサブクラスでスキャン方法で呼び出すことがClassPathMapperScannerdoScanにオーバーライドされたメソッドを。

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
    ……
    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        if (beanDefinitions.isEmpty()) {
            this.logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
        } else {
            this.processBeanDefinitions(beanDefinitions);
        }

        return beanDefinitions;
    }
    ……
}    复制代码

ここではsuper.doScan(basePackages)、コードはああ、あなたがソースコードを簡単に見て所有することができ、春の方法より物語よりも入れて、詳細知りたいはありません。

3.3、豆のプロキシ登録が完了し、SQLSESSIONを作成します

上記の工程を経て、今回はすべてのスキャンマッパーインターフェースを有すること、及びBeanDefinitionオブジェクトとして登録します。登録時間は、上記で使用されているdoScan方法processBeanDefinitionsアプローチ。

public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
    ……
    // 设置beanClass
    private MapperFactoryBean<?> mapperFactoryBean = new MapperFactoryBean();
    ……
    
    private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        Iterator var3 = beanDefinitions.iterator();

        while(var3.hasNext()) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var3.next();
            GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition();
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' mapperInterface");
            }
            // 将mapper接口的名称添加到构造参数
            definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
            // 设置BeanDefinition的class
            definition.setBeanClass(this.mapperFactoryBean.getClass());
            // 添加属性addToConfig
            definition.getPropertyValues().add("addToConfig", this.addToConfig);
            boolean explicitFactoryUsed = false;
            // 添加属性sqlSessionFactory
            if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
                definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
                explicitFactoryUsed = true;
            } else if (this.sqlSessionFactory != null) {
                definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
                explicitFactoryUsed = true;
            }

            if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
                if (explicitFactoryUsed) {
                    this.logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
                }

                definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
                explicitFactoryUsed = true;
            } else if (this.sqlSessionTemplate != null) {
                if (explicitFactoryUsed) {
                    this.logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
                }

                definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
                explicitFactoryUsed = true;
            }

            if (!explicitFactoryUsed) {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
                }

                definition.setAutowireMode(2);
            }
        }
    }
    ……
}    复制代码

処理中、比較的単純であるが、BeanDefinitionプロパティオブジェクトのいくつかを設定します。例えば:

  • 設定したbeanClass

セットBeanDefinitionオブジェクトたbeanClassですMapperFactoryBean この時間はMemberMapper登録使用するのと同じです:Springコンテナインタフェース現在のマッパーを、のbeanNameはmemberMapper、たbeanClassがMapperFactoryBean.classです。IOC春が初期化されたときにそのため、オブジェクトがMapperFactoryBeanオブジェクトをインスタンス化されます。

  • セットsqlSessionFactoryプロパティ

BeanDefinitionがオブジェクトとしてプロパティsqlSessionFactoryを追加し、オブジェクトが)(setSqlSessionFactoryへの呼び出しを容易にするために、PropertyValueをBeanDefinition時間を設定することです。

3.4、プロキシクラスSQLSESSIONを作成

最終setSqlSessionFactory、この方法では、SQLSESSIONはSqlSessionTemplateインスタンスで取得しました。SqlSessionTemplateオブジェクトでは、主にsqlSessionFactoryとsqlSessionProxy構成されており、sqlSessionProxyは、実際のプロキシオブジェクトSQLSESSIONインタフェースです。実際の呼び出しは、プロキシクラスのメソッドInvokeです。

public class MapperProxy<T> implements InvocationHandler, Serializable {
  ……
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }
  ……
}  复制代码

3.5まとめ

次のようにMapperプロキシ作成インターフェースは次のようになります。

  • BeanDefinitionとして登録対象となる走査経路マッパインタフェース基本パッケージ、1、すべてのオブジェクト
  • オブジェクトの2、及び設けられたbeanClass BeanDefinition sqlSessionFactory特性(ファクトリメソッドは、そのgetObjectメソッドを呼び出すときBeanDefinitionが取得れたオブジェクト、マッパー戻るプロキシクラスインターフェース)
  • 3、SqlSessionTemplateはコンストラクタを呼び出します設定sqlSessionFactoryプロパティは、プロキシクラスのインタフェースSQLSESSIONを作成します

最後に、我々はサービス層では、によって

@Resource 
private MemberMapper memberDao;复制代码

プロパティの中に注入すると、それは、プロキシクラスのリターンです。プロキシクラスのメソッド呼び出し方法memberDaoの実装は、実際に呼び出された場合。

第四に、開始の質問に答えるために

基本的なパッケージ構成を見つけるために、初期化SqlSessionFactoryBean中MyBatisのは、XMLファイル内のすべてを解決するためにスキャンパスが必要です。ただ、以下の二つの場所に焦点を当てます:

SqlSourceを作成します。1.

各タグはMyBatisのSQL SqlSourceは、オブジェクトをカプセル化します。次に、SQL文によっては、SQLは、動的および静的SQLに分かれています。その中でも、静的SQLは、いくつかのタイプに文字列のSQL文が含まれています。動的SQLが1 SqlNodeで構成されています。

MappedStatementを作成します。2.

各ラベル上のXMLファイルには、MappedStatement SQLは、オブジェクトに対応し、2つの非常に重要な属性があります。

  • ID

その完全修飾クラス名+メソッド名のID。

  • sqlSource

現在のラベルはSqlSource SQLオブジェクトに対応します。あなたが作成したMappedStatementオブジェクトを、それがキャッシュされますConfiguration#mappedStatementsで。

Configurationオブジェクトの初期化は、先に述べたように、我々はそれがMyBatisの設定の家政婦であることを知っている、すべての基本的な構成情報がここに維持されています。

そのようなAコード、例えば、以下

<!-- namespace的值就是全限定类名 -->
<mapper namespace="com.java.mmzsblog.dao.MemberMapper">
    ……
    <!-- select标签中id的值就是方法名,它和全限定类中的方法名是对应的 -->
    <select id="getMemberById" resultType="com.java.mmzsblog.entity.member">
        select * from member
        <where>
            <if test="memberId!=null">
                and member_id=#{memberId}
            </if>
        </where>
    </select>
    ……
</mapper>    复制代码

すべてのXMLが解析された後、コンフィギュレーションは、SQL情報のすべてが含まれています。そして、おそらくケースを完全なXMLを解析:

多分あなたはおそらく知っている、あなたのようにスマート、上の図を参照してください。我々はMyBatisのメソッドを実行すると、それがである全限定类名+方法名検索MappedStatementオブジェクト、その後、SQL内の内容を解析し、あなたが行うことができます。


国民の関心番号へようこそ。Javaの学習パス

個人のブログサイト:www.mmzsblog.cn


おすすめ

転載: juejin.im/post/5e0aa9ea5188254957632e73