parseConfiguration(XNode root)
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
- properties
- settings
- typeAliases タイプエイリアス
- typeHandlers 型プロセッサ
- objectFactory オブジェクト・ファクトリー
- plugins
- environments
- databaseIdProvider データベース・ベンダーの識別
- mappers
config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://.org/dtd/mybatis-3-.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/demo"/>
<property name="username" value="root"/>
<property name="password" value="98629"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
</configuration>
parseConfiguration に基づくコンフィグの結合.xml
< configuration >< environments >< mappers >あなたは、parseConfigurationメソッドは、設定ファイルを読み取るためにタグ名に基づいて、親タグで、それぞれ2つのサブタグがあり、次の2つのメソッドに対応している推測することができます。
< environments >< mappers >これは、タグ名に基づいて解析することが起こる、データソースで設定されているxmlファイルによると、設定されたマッパーマッピングファイルは、sqlステートメント内に書き込まれ、今、ブレークポイントを再生します。
environmentsElement(XNode context)---データ・ソースの読み込み
デバッグが開始され、ブレークポイントは、ルートノードの値の下に見つかったメソッドに設定され、それは、設定ファイルであることが起こるし、それはXNode.evalNode(文字列式)メソッドを呼び出すことが起こる さて、ルートオブジェクトは、変数パーサでXMLConfigBuilderクラスからであることが理解できます。XPathParserは、XMLファイルのコンテンツの値に格納されて
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
if (isSpecifiedEnvironment(id)) {
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
コードから、最初のタグ要素は、デフォルトの属性を取得することです、この属性の役割は、どのデータベースの設定を使用して、現在の状況を指定することです、つまり、どのノードの設定の使用は、デフォルトの値は、タグ要素のid値の構成です。そして、isSpecifiedEnvironmentメソッドが呼び出されます。
private boolean isSpecifiedEnvironment(String id) {
if (environment == null) {
throw new BuilderException("No environment specified.");
} else if (id == null) {
throw new BuilderException("Environment requires an id attribute.");
} else if (environment.equals(id)) {
return true;
}
return false;
}
対応するidがデフォルトで設定された値であるかどうかを判断するために、1つずつすべてをトラバースしながら、もしそうであれば、現在の要素がデータベース接続を初期化するために使用されます。
transactionManagerElement---トランザクションのロード
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}
Mybatisでは、JDBCとMANAGEDの2つの設定をサポートしています。ここでは、設定値の型に応じて、適切なトランザクションマネージャを返すために、JDBCとMANAGEDは、実際にConfigurationクラスで設定されていることがわかります。記事XMLConfigBuilderの親クラスBaseBuilderでBaseBuilderコンストラクタのパラメータは、Configurationオブジェクトの初期化であり、Configurationオブジェクトの初期化時に、組み込みのエイリアスレジストリTypeAliasRegistryは、JDBCとMANAGEDを含むデフォルトのエイリアスを登録します。JDBCやMANAGEDを含みます。
dataSourceElement---データソースをロード
dataSourceElement のソースコードを見る
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
JDBCで必要なデータを構成に設定します。
概要
mapperElement(root.evalNode("mappers"))-マッピング XML ファイルを読み込みます。
いわゆるMybatisの本質は、xmlコンフィギュレーション・ファイルの下にあるmappersノードかもしれません!
<mappers>
<mapper resource="mapper/UserMapper.xml"></mapper>
</mappers>
mapper/UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://.org/dtd/mybatis-3-.dtd">
<mapper namespace="mapper.UserMapper">
<!-- FindUserbyid-->
<select id="selectById" resultType="domain.User" parameterType="int">
select * from user where id = #{id}
</select>
<!-- FindAll-->
<select id="selectAll" resultType="domain.User">
select * from user
</select>
<!-- 一対一のルックアップ>
<select id="selectInfo" parameterType="int" resultMap="StudentAndUserSelect">
select student.*,user.*
from student,user
where student.id=user.id and user.id = #{id}
</select>
<resultMap id="StudentAndUserSelect" type="domain.Json.UserAndStudent">
<association property="user" javaType="domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="password" column="password"></result>
</association>
<association property="student" javaType="domain.Student">
<id property="id" column="id"></id>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
</association>
</resultMap>
<!-- 一対多ルックアップ>
<select id="selectCourse" parameterType="int" resultMap="StudentAndCourseSelect">
SELECT s.*,c.*
from student s
INNER JOIN course c
on s.id = c.student_id
where c.student_id =#{id}
</select>
<resultMap id="StudentAndCourseSelect" type="domain.Json.StudentAndCourse">
<collection property="students" ofType="domain.Student">
<id property="id" column="id"></id>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
</collection>
<collection property="courses" ofType="domain.Course">
<id property="id" column="id"></id>
<result property="student_id" column="student_id"></result>
<result property="course" column="course"></result>
</collection>
</resultMap>
</mapper>
ソースコードを見てみましょう
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
//パッケージ・ノードかどうかを検出する
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
} else {
// <mapper resource="mapper/UserMapper.xml"></mapper>のマッパー/UserMapper は、XML ファイルを読み込む。.xml,すなわちリソース= "mapper/UserMapper.xml"
String resource = child.getStringAttribute("resource");
//マッパー・ノードの url 属性を読み込む
String url = child.getStringAttribute("url");
//マッパー・ノードの class 属性を読み込む
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
//rusource に基づいてマッパーファイルを読み込む
ErrorContext.instance().resource(resource);
//ファイルのバイトストリームを読み込む
InputStream inputStream = Resources.getResourceAsStream(resource);
//マッパー・パーサーのインスタンス化
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
//マッパーファイルのパース、すなわちマッパー/ユーザーダオマッピングのパースを実行する.xml,
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
//Web urlリソースからマッパーファイルをロードする
ErrorContext.instance().resource(url);
InputStream inputStream = Resources.getUrlAsStream(url);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url == null && mapperClass != null) {
//mapperClass を使ってファイルを読み込む
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
//resource,url,mapperClass3つのコンフィギュレーション・メソッドのうち1つしか使用できない。
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
マッパー内のマッパーノードを繰り返し、一つずつ解析するのは明らかです。マッパー設定ファイルにはマッパーノードが1つしかないので、ここで解析するのはmapper/UserMapper.xmlファイルです。ここでデバッグモードでブレークポイントを作ります。
//マッパー・パーサーのインスタンス化
    XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
    //マッパーファイルのパース、すなわちマッパー/ユーザーダオマッピングのパースを実行する.xml,
    mapperParser.parse();
マッパー・パーサーのインスタンス化: XMLMapperBuilder
public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
configuration, resource, sqlFragments);
}
そのthisキーワードでプライベートメソッドを呼び出します。
private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
super(configuration);
this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
this.parser = parser;
this.sqlFragments = sqlFragments;
this.resource = resource;
}
新しいクラスMapperBuilderAssistantの内部では、その役割はXMLファイルの解析を支援することです。 同様に、MapperBuilderAssistantクラスはBaseBuilderから継承されています。しかし、次の分析をよりよく行うためには、Configuration クラスのプロパティとメソッドのいくつかを知っておく必要があります。
public class Configuration {
protected Environment environment;
protected Properties variables = new Properties();
......
//値をnullに初期化する
protected String databaseId;
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
// これは構文解析された sql 宣言を格納する HashMap で、キーは文字列型である。.zcz.learnmybatis.entity.User.findUserById,値は MappedStatement インスタンス・オブジェクトである。
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
protected final Map<String, KeyGenerator> keyGenerators = new StrictMap<KeyGenerator>("Key Generators collection");
......
//これは、ロードされパースされたマッパーファイルの名前を保持する、順序付けされていない非繰り返しの Set コレクションである。例えば<mapper resource="mapper/userDao-mapping.xml"/>のマッパー/ユーザーダオマッピングは、XML ファイルを読み込む。.xml
protected final Set<String> loadedResources = new HashSet<String>();
......
//sqlフラグメントマップ、キー文字列値XNode、このマップは、前のマッパーで解析されたフラグメントに格納されている
protected final Map<String, XNode> sqlFragments = new StrictMap<XNode>("XML fragments parsed from previous mappers");
......
public Configuration() {
.....
// デフォルトの XML 言語ドライバを登録する
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
}
......
//LoadParsingCompleteSet loadedResources にリソースを追加する。
public void addLoadedResource(String resource) {
loadedResources.add(resource);
}
//マッパーファイルがロードされ、パースされたかどうかを検出する。<mapper resource="mapper/userDao-mapping.xml"/>リソース内の
public boolean isResourceLoaded(String resource) {
return loadedResources.contains(resource);
}
......
//ラベル宣言クラスインスタンスオブジェクトIDに従って、解析されたラベル宣言クラスインスタンスオブジェクトを取得する
// タグ宣言とは何か?
public MappedStatement getMappedStatement(String id) {
return this.getMappedStatement(id, true);
}
//ラベル宣言クラスインスタンスオブジェクトIDに従って、解析されたラベル宣言クラスインスタンスオブジェクトを取得する
public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
if (validateIncompleteStatements) {
buildAllStatements();
}
return mappedStatements.get(id);
}
//sql フラグメントを取得する
public Map<String, XNode> getSqlFragments() {
return sqlFragments;
}
......
// statementNameという名前のタグ宣言が存在するかどうかのチェックに基づいている。
public boolean hasStatement(String statementName) {
return hasStatement(statementName, true);
}
// statementNameという名前のタグ宣言が存在するかどうかのチェックに基づいている。
public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {
if (validateIncompleteStatements) {
buildAllStatements();
}
return mappedStatements.containsKey(statementName);
}
......
}
mapperParser.parse();; mapperParser.parse(); mapperParser.parse()
さて、ブレークポイント前のメソッドでxmlファイルをどのようにパースしているか詳しく見ることができます。
public void parse() {
// 最初にマッパーファイルが解析されたかどうかを判断する
if (!configuration.isResourceLoaded(resource)) {
//構文解析を行う
configurationElement(parser.evalNode("/mapper"));
//解析レコードを保存する
configuration.addLoadedResource(resource);
// すでにパースされた名前空間をバインドする
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
マッパーファイルをパースする実際のコードはconfigurationElementメソッドであることがわかります。
private void configurationElement(XNode context) {
try {
//マッパー・ファイルのマッパー・ノードの namespace 属性を取得する mapper.UserMapper
String namespace = context.getStringAttribute("namespace");
if (namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
//マッピング・マッパー・パーサー・アシスタント builderAssistant に名前空間を割り当てる.currentNameSpace,つまり、マッパー・パーサー・アシスタントがマッパー・ファイルを解析していることを伝える。
builderAssistant.setCurrentNamespace(namespace);
//キャッシュ参照ノードを解析する
cacheRefElement(context.evalNode("cache-ref"));
//キャッシュ・ノードを解析する
cacheElement(context.evalNode("cache"));
//parameterMap "を直接使うのではなく、"/mapper/parameterMap "を使うのは、parameterMap は複数設定できるからである。.evalNodesメソッドは evalNode ではなく evalNodes になっている。
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//resultMap ノードを解析する
resultMapElements(context.evalNodes("/mapper/resultMap"));
//sql ノードを解析する
sqlElement(context.evalNodes("/mapper/sql"));
//ParseSelect|insert|update|deleteノード、コンテキストに注意.evalNodes()メソッドを呼び出す。
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
}
}
上記のコードから、名前空間を処理した後、マッパーファイルのノードを解決することです ノードを解決した後、buildStatementFromContextメソッドのソースコードを分析してみましょう。
private void buildStatementFromContext(List<XNode> list) {
   //これがコンフィギュレーションだ。.getDatabaseId なぜなら、コンフィギュレーションが初期化されるときにはデフォルト値が与えられず、コンフィギュレーション・オブジェクトが仮想マシンによってインスタンス化されるときにはデフォルト値として null が与えられるからである。
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
buildStatementFromContext(list, null);
}
そして、buildStatementFromContextオーバーロードメソッドを呼び出し、このメソッドはすべてのラベル宣言を繰り返し、1つずつ解析します。
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
    //タグ宣言パーサーを初期化する
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
      // タグ宣言の解析を実行する
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
XMLStatementBuilder正式に XML の走査を開始
同じXMLStatementBuilderはまた、BaseBuilderから継承されています。次のコンストラクタを見るにはクリックしてください
public XMLStatementBuilder(Configuration configuration, MapperBuilderAssistant builderAssistant, XNode context, String databaseId) {
super(configuration);
this.builderAssistant = builderAssistant;
this.context = context;
this.requiredDatabaseId = databaseId;
}
public void parseStatementNode() {
String id = context.getStringAttribute("id");
String databaseId = context.getStringAttribute("databaseId");
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String parameterType = context.getStringAttribute("parameterType");
Class<?> parameterTypeClass = resolveClass(parameterType);
String resultMap = context.getStringAttribute("resultMap");
String resultType = context.getStringAttribute("resultType");
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
Class<?> resultTypeClass = resolveClass(resultType);
String resultSetType = context.getStringAttribute("resultSetType");
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
String nodeName = context.getNode().getNodeName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
// Include Fragments before parsing
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
// Parse selectKey after includes and remove them.
processSelectKeyNodes(id, parameterTypeClass, langDriver);
// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
String resultSets = context.getStringAttribute("resultSets");
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
一見したところ、タグの内容を取得するためのものです。
databaseIdMatchesCurrent
//databaseIdとrequiredDatabaseIdの両方がNULLの状態で、必要なdatabaseIdをタグ宣言のdatabaseIdと比較する。
private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
if (requiredDatabaseId != null) {
if (!requiredDatabaseId.equals(databaseId)) {
//異なる場合はfalseを返し、パースを停止する
return false;
}
} else {
if (databaseId != null) {
// 今回は requiredDatabaseId== null, このrequiredDatabaseIdの場合nullに等しいdatabaseIdがnullに等しくない、つまり、databaseIdを使用する必要性とdatabaseIdのラベル宣言が同じではない、falseに戻し、解析を停止する。
return false;
}
// skip this statement if there is a previous one with a not null databaseId すでに解析済みのタグ宣言があり、databaseId が NULL でない場合は、false を返して解析をスキップする。
// idを取得する。このidはラベル・パーサーのidで、次の分析ではっきりわかる:このidは、ラベル宣言クラスによってインスタンス化されたオブジェクトのidでもある。
id = builderAssistant.applyCurrentNamespace(id, false);
if (this.configuration.hasStatement(id, false)) {
MappedStatement previous = this.configuration.getMappedStatement(id, false); // issue #2
if (previous.getDatabaseId() != null) {
return false;
}
}
}
return true;
}
langDriver.createSqlSource();sql 文の処理
このメソッドは#{}, {"が存在するかどうかを処理してSQL文が動的SQL文かどうかを判定し、select * from user where id = #{id}をselect * from user where id = ?また、idを#{id}に保存します。
builderAssistant.addMappedStatementMappedStatement オブジェクトへの変換例
もっと簡単に言うと
<select id="selectById" resultType="domain.User" parameterType="int">
select * from user where id = #{id}
</select>
をMappedStatementオブジェクトに変換し、以下のようにコンフィギュレーションに保持するだけです。
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
if (unresolvedCacheRef) throw new IncompleteElementException("Cache-ref not yet resolved");
id = applyCurrentNamespace(id, false);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
  //MappenStatement を初期化する.Builder
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType);
statementBuilder.resource(resource);
statementBuilder.fetchSize(fetchSize);
statementBuilder.statementType(statementType);
statementBuilder.keyGenerator(keyGenerator);
statementBuilder.keyProperty(keyProperty);
statementBuilder.keyColumn(keyColumn);
statementBuilder.databaseId(databaseId);
statementBuilder.lang(lang);
statementBuilder.resultOrdered(resultOrdered);
statementBuilder.resulSets(resultSets);
setStatementTimeout(timeout, statementBuilder);
setStatementParameterMap(parameterMap, parameterType, statementBuilder);
setStatementResultMap(resultMap, resultType, resultSetType, statementBuilder);
setStatementCache(isSelect, flushCache, useCache, currentCache, statementBuilder);
  // MappedStatement を構築する
MappedStatement statement = statementBuilder.build();
  //
configuration.addMappedStatement(statement);
return statement;
}
ここで、最初の select id="selectById" タグ宣言の解析が完了し、XMLStatementBuilder クラスを経由して、Mapper ファイルの解析が終了するまで、次をトラバースしていきます。
概要:
XMLConfigBuilderオブジェクトのparseConfigurationメソッドを介して、xmlファイルを解析するノードによると、マッパーのノード解決が完了し、すべてのmybatis設定ファイルが解析されている 彼らは最終的にオブジェクトを提供する最終的な設定オブジェクトです。
Mybatisのソースコード--- SqlSessionFactoryBuilder(設定ファイルを取得するには)
Mybatisソースコード --- parseConfiguration 読み込み XML ファイル
Mybatis のソース・コード --- SqlSession による sql クエリの実行
Mybatis のソースコード --- SqlSession による動的エージェントの完成
Mybatisのソースコード --- SqlSessionの4つの主要オブジェクト
Mybatis ソース・コード --- キャッシュ
個人的な意見です。議論へようこそ、個人ブログ





