该节内容主要将Mybatis初始化内容,回顾下我们第一节的核心重点图。
举个case:Mybatis初始化的加载过程时序图
3.1、XML的配置解析示例
3.1.1、mybatis-config.xml的使用示例
//1、xml的协议头
<?xml version="1.0" encoding="UTF-8" ?>
//2、mybatis对于xml,Configuration配置文件的约束协议
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
//3、全局配置对象
<configuration>
//3.1.1、数据源配置1:通过属性注入数据源
<properties resource="org/apache/ibatis/databases/blog/blog-derby.properties"/>
//3.1.2、数据源配置2:通过直接配置
//3.2、全局配置对象的属性
<settings>
//是否开启缓存
<setting name="cacheEnabled" value="true"/>
//是否开启懒加载
<setting name="lazyLoadingEnabled" value="false"/>
//是否允许返回多个结果集
<setting name="multipleResultSetsEnabled" value="true"/>
//是否使用驼峰标示属性
<setting name="useColumnLabel" value="true"/>
//是否使用生成主键策略
<setting name="useGeneratedKeys" value="false"/>
//默认的执行器类型
<setting name="defaultExecutorType" value="SIMPLE"/>
//默认的会话超时时间单位s
<setting name="defaultStatementTimeout" value="25"/>
</settings>
//3.3、实体对象别名映射
<typeAliases>
<typeAlias alias="Author" type="org.apache.ibatis.domain.blog.Author"/>
</typeAliases>
//3.3、指定类型处理器
<typeHandlers>
<typeHandler javaType="String" jdbcType="VARCHAR" handler="org.apache.ibatis.builder.CustomStringTypeHandler"/>
</typeHandlers>
//3.4、对象工厂
<objectFactory type="org.apache.ibatis.builder.ExampleObjectFactory">
<property name="objectFactoryProperty" value="100"/>
</objectFactory>
//3.5、配置会话拦截插件
<plugins>
<plugin interceptor="org.apache.ibatis.builder.ExamplePlugin">
<property name="pluginProperty" value="100"/>
</plugin>
</plugins>
//3.6、配置环境变量: MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)
<environments default="development">
//3.6.1、环境配置变量可以通过ID来区分dev-uat-pre-pro
<environment id="development">
//3.6.1.1、事务管理器
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
//3.6.1.2、数据源配置
<dataSource type="UNPOOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
//3.7、mapper接口配置,包含了 SQL 代码和映射定义信息
<mappers>
<mapper resource="org/apache/ibatis/builder/AuthorMapper.xml"/>
</mappers>
</configuration>
3.1.2、Mapper.xml的使用示例
//1、xml的定义
<?xml version="1.0" encoding="UTF-8" ?>
//2、mapper协议的约束
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
//3、映射类路径的mapper,实际上是和对应的java类绑定
<mapper namespace="org.apache.ibatis.domain.blog.mappers.AuthorMapper">
//4、mapper接口方法:根据主键ID查询返回结果map的
<parameterMap id="selectAuthor" type="org.apache.ibatis.domain.blog.Author">
<parameter property="id" />
</parameterMap>
//5、mapper接口方法:对于实体对象和数据库字段的映射情况
<resultMap id="selectAuthor" type="org.apache.ibatis.domain.blog.Author">
//字段列和对象属性的映射
<id column="id" property="id" />
<result property="username" column="username" />
<result property="favouriteSection" column="favourite_section" />
</resultMap>
//6、mapper接口方法:包含嵌套的对象属性字段映射情况
<resultMap id="selectImmutableAuthor" type="org.apache.ibatis.domain.blog.ImmutableAuthor">
//参数和Java类型映射
<constructor>
<idArg column="id" javaType="_int" />
<arg column="username" javaType="string" />
<arg column="favourite_section" javaType="org.apache.ibatis.domain.blog.Section" />
</constructor>
</resultMap>
//7、mapper接口方法:查询所有结果
<select id="selectAllAuthors" resultType="org.apache.ibatis.domain.blog.Author">
select * from author
</select>
//8、mapper接口方法:查询返回set集
<select id="selectAllAuthorsSet" resultType="org.apache.ibatis.domain.blog.Author">
select * from author
</select>
//9、mapper接口方法:查询返回list集合
<select id="selectAllAuthorsLinkedList" resultType="org.apache.ibatis.domain.blog.Author">
select * from author
</select>
//10、mapper接口方法:查询返回数组
<select id="selectAllAuthorsArray" resultType="org.apache.ibatis.domain.blog.Author">
select * from author
</select>
//11、mapper接口方法:查询只返回部分参数
<select id="selectAuthorLinkedHashMap" resultType="java.util.LinkedHashMap">
select id, username from author where id = #{value}
</select>
//12、mapper接口方法:查询绑定外部传入参数
<select id="selectAuthor" parameterMap="selectAuthor" resultMap="selectAuthor">
select id, username, password, email, bio, favourite_section
from author where id = ?
</select>
//13、mapper接口方法:查询指定入参类型的参数
<select id="selectAuthorWithInlineParams" parameterType="int"
resultType="org.apache.ibatis.domain.blog.Author">
select * from author where id = #{id}
</select>
//14、mapper接口方法:插入实体对象映射
<insert id="insertAuthor" parameterType="org.apache.ibatis.domain.blog.Author">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
//15、mapper接口方法:更新实体对象映射
<update id="updateAuthor" parameterType="org.apache.ibatis.domain.blog.Author">
update Author
set username=#{username,
javaType=String},
password=#{password},
email=#{email},
bio=#{bio}
where id=#{id}
</update>
//16、mapper接口方法:删除实体根据主键ID
<delete id="deleteAuthor" parameterType="int">
delete from Author where id = #{id}
</delete>
//17、mapper接口方法:有选择更新字段
<update id="updateAuthorIfNecessary" parameterType="org.apache.ibatis.domain.blog.Author">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
//18、mapper接口方法:根据指定的条件进行查询
<select id="selectWithOptions" resultType="org.apache.ibatis.domain.blog.Author"
fetchSize="200" timeout="10" statementType="PREPARED" resultSetType="SCROLL_SENSITIVE" flushCache="false" useCache="false">
select * from author
</select>
</mapper>
3.1.3、代码中XML的配置解析使用示例
3.1.3.1、从 XML 中构建 SqlSessionFactory
根据Mybatis核心设计图其实可以观察到,整个Mybatis的核心在于一个SqlSession的一系列操作:实体对象和SQL的绑定,执行会话,结果集处理。而SqlSession的管理则来自于SqlSessionFactory,SqlSessionFactory是可以通过SqlSessionFactoryBuilder获得构建。如何构建出符合用户的SqlSessionFactory,则依赖于我们上面提到的Configuration 实例(Mybatis-config.xml)。
⚠️:强调下重点:每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的,SqlSessionFactory 的实例是通过SqlSessionFactoryBuilder从Configuration 实例(Mybatis-config.xml)构建出来的。
从 XML 文件中构建 SqlSessionFactory 的实例非常简单,可以使用类路径下的资源文件进行配置。也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类可以通过它来获取资源输入流(可以参考之后的源码明细篇)。
//我们上面3.1.1节提到的配置文件全路径
String resource = "org/mybatis/example/mybatis-config.xml";
//通过Mybatis提供的Resources工具类获取输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//根据Mybatis提供的SqlSessionFactoryBuilder构建器构建用户定义的Configuration特有的SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
3.1.3.2、构建我们真正干活的SqlSession
//SqlSessionFactory 中获取 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession()
//执行上面我们3.1.2节提到的配置文件mapper中的方法,因为xml配置好的映射关系所以我们直接是通过sqlSession就可以拿到映射的mapper,怎么拿到的呢?依然是需要看下第二章中我提到的Mybatis核心设计图,通过动态代理的方式从Configuration对象中找到对应的mapper,method,parameter。所以从这里看Configuration就是整个一个仓库拥有所有你需要的东西。
//从会话中获取绑定好的mapper接口信息
AuthorMapperWithAnnotation mapper = sqlSession.getMapper(AuthorMapperWithAnnotation.class);
//执行mapper接口的实现方法,而这段具体分析就到第四章和第五章可以学习源码,第三章主要将全局初始化这个过程。
Author author = mapper.selectAuthorInfoById(101);
3.2、注解的配置解析示例
3.2.1、Mybatis-config.xml的使用示例
当然这里也可以使用properties文件属性等内容,或者springboot的yml文件等配置。
//1、xml的协议约束
<?xml version="1.0" encoding="UTF-8" ?>
//2、Configuration的协议约束
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
//3、全局配置类的约束
<configuration>
//3.1、全局配置的属性和事务管理器
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="" value=""/>
</transactionManager>
<dataSource type="UNPOOLED">
<property name="driver" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:automapping"/>
<property name="username" value="sa"/>
</dataSource>
</environment>
</environments>
</configuration>
3.2.2、Mapper接口的使用示例
根据我们接口常用的CRUD操作这里分别提供了注解的实现方法形式。
public interface AuthorMapperWithAnnotation {
//使用select注解直接查询
@Select("select id, username, password, email, bio, favourite_section from author where id = #{id}")
Author selectAuthorInfoById(int id);
//使用SelectProvider注解直接查询
@SelectProvider(type =AuthorProvider.class,method = "selectAuthorWithPlaceholder")
Author selectAuthorWithPlaceholder(Author author);
//使用Insert注解直接查询
@Insert("insert into author (id,username,password,email,bio) values (#{id},#{username},#{password},#{email},#{bio})")
int insertAuthor(Author author);
//使用InsertProvider注解直接查询
@InsertProvider(type =AuthorProvider.class,method = "insertAuthorWithPlaceholder")
int insertAuthorWithPlaceholder(Author author);
//使用Update注解直接查询
@Update("update author set username=#{username} where id =#{id}")
int updateAuthor(Author author);
//使用UpdateProvider注解直接查询
@UpdateProvider(type =AuthorProvider.class,method = "updateAuthorWithPlaceholder")
void updateAuthorWithPlaceholder(Author author);
//使用Delete注解直接查询
@Delete("delete from author where id = #{id}")
int deleteAuthor(Author author);
//使用DeleteProvider注解直接查询
@DeleteProvider(type =AuthorProvider.class,method = "deleteAuthorWithPlaceholder")
int deleteAuthorWithPlaceholder(Author author);
//提供provider注解类的对应方法
class AuthorProvider{
//selectAuthorWithPlaceholder方法
public String selectAuthorWithPlaceholder(Author author){
return new SQL(){{
SELECT("id,username,password,email,bio").FROM("author").WHERE("id=#{id}");
}}.toString();
}
//insertAuthorWithPlaceholder方法
public String insertAuthorWithPlaceholder(Author author){
return new SQL(){{
INSERT_INTO("Author").VALUES("id,username,password,email,bio","#{id},#{username},#{password},#{email},#{bio}");
}}.toString();
}
//updateAuthorWithPlaceholder方法
public String updateAuthorWithPlaceholder(Author author){
return new SQL(){{
UPDATE("Author").SET("id=#{id}","username=#{username}","password=#{password}","email=#{email}","bio=#{bio}").WHERE("id=#{id}");
}}.toString();
}
//deleteAuthorWithPlaceholder方法
public String deleteAuthorWithPlaceholder(Author author){
return new SQL(){{
DELETE_FROM("Author").WHERE("id=#{id}");
}}.toString();
}
}
}
3.3.3、代码中注解的解析使用示例
//上述提到的输入流信息我们这里先以xml为例子
final String resource = "org/apache/ibatis/builder/Mybatis-config.xml";
final Reader reader = Resources.getResourceAsReader(resource);
//直接代码构建SqlSessionFactory
SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);
//初始化全局配置---相当于Mybatis-config.xml中的绑定configuration标签
Configuration configuration = new Configuration(sqlMapper.getConfiguration().getEnvironment());
//为全局配置添加需要的Mapper接口---相当于Mybatis-config.xml中的绑定Mapper.xml文件的标签
configuration.addMapper(AuthorMapperWithAnnotation.class);
//创建SQL会话工厂---利用SqlSessionFactory实现Bean实例化
SqlSessionFactory sqlMapperWithAnnotation = new DefaultSqlSessionFactory(configuration);
//获取SQL会话链接---所有Mybatis的核心API接口
SqlSession sqlSession = sqlMapperWithAnnotation.openSession();
//从会话中获取绑定好的mapper接口信息---利用反射获取对应的mapper
AuthorMapperWithAnnotation mapper = sqlSession.getMapper(AuthorMapperWithAnnotation.class);
//执行插入会话---Mybatis核心设计图中动态代理执行过程(这里的源码分析可以参考第四章、第五章)
Author expected = new Author(500, "wolf:\"test\"", "******", "liuxiaocheng@somewhere.com", "Something...", null);
mapper.insertAuthorWithPlaceholder(expected);
3.3、核心类和核心方法
- SqlSessionFactoryBuilder:SqlSessionFactory的构造器,可以自己解析配置,也可以通过提前构建好的配置对象构建。
- SqlSessionFactory:管理数据库会话、聚合Configuration的属性。
- Configuration:是全局所有的运行数据配置,相当于一个大的仓库。
- XMLConfigBuilder:解析XML的Configuration构建器。
- XMLMapperBuilder:解析XML的Mapper构建器。
根据时序图我们可以看到实际上分为三个过程【创建】-》【解析】-》【构建】
3.3.1、SqlSessionFactoryBuilder源码分析
public class SqlSessionFactoryBuilder {
//根据字符流构建会话工厂
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
...省略本次无关内容...
//根据字符流和环境和属性构建会话工厂
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
//利用xml配置构建器
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
...省略本次无关内容...
//根据全局配置构建会话工厂,走默认的会话工厂
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
3.3.2、SqlSessionFactory源码分析
3.3.2.1、SqlSessionFactory源码分析
/*
*从连接或数据源创建SqlSession
*/
public interface SqlSessionFactory {
//打开会话
SqlSession openSession();
//打开会话是否自动提交
SqlSession openSession(boolean autoCommit);
//打开链接的session
SqlSession openSession(Connection connection);
//打开事务隔离级别的session
SqlSession openSession(TransactionIsolationLevel level);
//打开执行器类型的session
SqlSession openSession(ExecutorType execType);
//打开执行器类型,是否自动提交的session
SqlSession openSession(ExecutorType execType, boolean autoCommit);
//打开执行器和事务隔离级别机制的session
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
//打开执行器,链接的session
SqlSession openSession(ExecutorType execType, Connection connection);
//获取全局配置
Configuration getConfiguration();
}
3.3.2.2、DefaultSqlSessionFactory源码分析
/**
* 默认的会话工厂
* @author Clinton Begin
*/
public class DefaultSqlSessionFactory implements SqlSessionFactory {
//全局配置
private final Configuration configuration;
//构造函数
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
...省略本次无关内容...
}
3.3.3、Configuration源码分析
/**
* 抽象构建器
* @author Clinton Begin
*/
public abstract class BaseBuilder {
//全局配置
protected final Configuration configuration;
//类型别名注册器
protected final TypeAliasRegistry typeAliasRegistry;
//类型处理器注册器
protected final TypeHandlerRegistry typeHandlerRegistry;
//构造函数
public BaseBuilder(Configuration configuration) {
this.configuration = configuration;
this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
}
//获取全局配置
public Configuration getConfiguration() {
return configuration;
}
//解析正则表达式
protected Pattern parseExpression(String regex, String defaultValue) {
return Pattern.compile(regex == null ? defaultValue : regex);
}
//获取boolean值
protected Boolean booleanValueOf(String value, Boolean defaultValue) {
return value == null ? defaultValue : Boolean.valueOf(value);
}
//获取int值
protected Integer integerValueOf(String value, Integer defaultValue) {
return value == null ? defaultValue : Integer.valueOf(value);
}
//获取set值
protected Set<String> stringSetValueOf(String value, String defaultValue) {
value = value == null ? defaultValue : value;
return new HashSet<>(Arrays.asList(value.split(",")));
}
//解析jdbc类型
protected JdbcType resolveJdbcType(String alias) {
if (alias == null) {
return null;
}
try {
return JdbcType.valueOf(alias);
} catch (IllegalArgumentException e) {
throw new BuilderException("Error resolving JdbcType. Cause: " + e, e);
}
}
//解析结果集类型
protected ResultSetType resolveResultSetType(String alias) {
if (alias == null) {
return null;
}
try {
return ResultSetType.valueOf(alias);
} catch (IllegalArgumentException e) {
throw new BuilderException("Error resolving ResultSetType. Cause: " + e, e);
}
}
//解析参数风格
protected ParameterMode resolveParameterMode(String alias) {
if (alias == null) {
return null;
}
try {
return ParameterMode.valueOf(alias);
} catch (IllegalArgumentException e) {
throw new BuilderException("Error resolving ParameterMode. Cause: " + e, e);
}
}
//创建实例
protected Object createInstance(String alias) {
Class<?> clazz = resolveClass(alias);
if (clazz == null) {
return null;
}
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new BuilderException("Error creating instance. Cause: " + e, e);
}
}
//根据别名解析类
protected <T> Class<? extends T> resolveClass(String alias) {
if (alias == null) {
return null;
}
try {
return resolveAlias(alias);
} catch (Exception e) {
throw new BuilderException("Error resolving class. Cause: " + e, e);
}
}
//解析类型处理器
protected TypeHandler<?> resolveTypeHandler(Class<?> javaType, String typeHandlerAlias) {
if (typeHandlerAlias == null) {
return null;
}
Class<?> type = resolveClass(typeHandlerAlias);
if (type != null && !TypeHandler.class.isAssignableFrom(type)) {
throw new BuilderException("Type " + type.getName() + " is not a valid TypeHandler because it does not implement TypeHandler interface");
}
@SuppressWarnings("unchecked") // already verified it is a TypeHandler
Class<? extends TypeHandler<?>> typeHandlerType = (Class<? extends TypeHandler<?>>) type;
return resolveTypeHandler(javaType, typeHandlerType);
}
//解析类型处理器
protected TypeHandler<?> resolveTypeHandler(Class<?> javaType, Class<? extends TypeHandler<?>> typeHandlerType) {
if (typeHandlerType == null) {
return null;
}
// javaType ignored for injected handlers see issue #746 for full detail
TypeHandler<?> handler = typeHandlerRegistry.getMappingTypeHandler(typeHandlerType);
if (handler == null) {
// not in registry, create a new one
handler = typeHandlerRegistry.getInstance(javaType, typeHandlerType);
}
return handler;
}
//解析别名
protected <T> Class<? extends T> resolveAlias(String alias) {
return typeAliasRegistry.resolveAlias(alias);
}
}
3.3.4.1、XMLConfigBuilder源码分析
/**
* xml配置构建器
* @author Clinton Begin
* @author Kazuki Shimizu
*/
public class XMLConfigBuilder extends BaseBuilder {
//是否解析
private boolean parsed;
//解析器
private final XPathParser parser;
//环境
private String environment;
//本地反射工厂
private final ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
//构造函数
public XMLConfigBuilder(Reader reader) {
this(reader, null, null);
}
//构造函数
public XMLConfigBuilder(Reader reader, String environment) {
this(reader, environment, null);
}
//构造函数
public XMLConfigBuilder(Reader reader, String environment, Properties props) {
this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}
//构造函数
public XMLConfigBuilder(InputStream inputStream) {
this(inputStream, null, null);
}
//构造函数
public XMLConfigBuilder(InputStream inputStream, String environment) {
this(inputStream, environment, null);
}
//构造函数
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
//私有构造函数
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
//解析全局配置对象
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
//解析全局配置对象
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
//解析属性变量节点
propertiesElement(root.evalNode("properties"));
//解析setting节点字段
Properties settings = settingsAsProperties(root.evalNode("settings"));
//加载用户自定义的VFS解析文件类
loadCustomVfs(settings);
//加载用户自定义的日志实现
loadCustomLogImpl(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"));
//数据库ID
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//类型处理器元素
typeHandlerElement(root.evalNode("typeHandlers"));
//mapper接口元素
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
//设置属性
private Properties settingsAsProperties(XNode context) {
if (context == null) {
return new Properties();
}
Properties props = context.getChildrenAsProperties();
//检查所有的setting设置是在配置类中已知的
// Check that all settings are known to the configuration class
MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
for (Object key : props.keySet()) {
if (!metaConfig.hasSetter(String.valueOf(key))) {
throw new BuilderException("The setting " + key + " is not known. Make sure you spelled it correctly (case sensitive).");
}
}
return props;
}
//加载定制vfs解析实现类
private void loadCustomVfs(Properties props) throws ClassNotFoundException {
String value = props.getProperty("vfsImpl");
if (value != null) {
String[] clazzes = value.split(",");
for (String clazz : clazzes) {
if (!clazz.isEmpty()) {
@SuppressWarnings("unchecked")
Class<? extends VFS> vfsImpl = (Class<? extends VFS>)Resources.classForName(clazz);
configuration.setVfsImpl(vfsImpl);
}
}
}
}
//加载定制实现类
private void loadCustomLogImpl(Properties props) {
Class<? extends Log> logImpl = resolveClass(props.getProperty("logImpl"));
configuration.setLogImpl(logImpl);
}
//类型别名元素
private void typeAliasesElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String typeAliasPackage = child.getStringAttribute("name");
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
} else {
String alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type");
try {
Class<?> clazz = Resources.classForName(type);
if (alias == null) {
typeAliasRegistry.registerAlias(clazz);
} else {
typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException e) {
throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
}
}
}
}
}
//插件元素
private void pluginElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
String interceptor = child.getStringAttribute("interceptor");
Properties properties = child.getChildrenAsProperties();
Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).getDeclaredConstructor().newInstance();
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}
//对象工厂元素
private void objectFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties properties = context.getChildrenAsProperties();
ObjectFactory factory = (ObjectFactory) resolveClass(type).getDeclaredConstructor().newInstance();
factory.setProperties(properties);
configuration.setObjectFactory(factory);
}
}
//对象包装工厂元素
private void objectWrapperFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).getDeclaredConstructor().newInstance();
configuration.setObjectWrapperFactory(factory);
}
}
//反射工厂元素
private void reflectorFactoryElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
ReflectorFactory factory = (ReflectorFactory) resolveClass(type).getDeclaredConstructor().newInstance();
configuration.setReflectorFactory(factory);
}
}
//属性元素
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
Properties defaults = context.getChildrenAsProperties();
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
if (resource != null && url != null) {
throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
}
if (resource != null) {
defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
defaults.putAll(Resources.getUrlAsProperties(url));
}
Properties vars = configuration.getVariables();
if (vars != null) {
defaults.putAll(vars);
}
parser.setVariables(defaults);
configuration.setVariables(defaults);
}
}
//设置属性
private void settingsElement(Properties props) {
configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
configuration.setDefaultResultSetType(resolveResultSetType(props.getProperty("defaultResultSetType")));
configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
configuration.setDefaultEnumTypeHandler(resolveClass(props.getProperty("defaultEnumTypeHandler")));
configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
configuration.setLogPrefix(props.getProperty("logPrefix"));
configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
}
//环境元素
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服务元素
private void databaseIdProviderElement(XNode context) throws Exception {
DatabaseIdProvider databaseIdProvider = null;
if (context != null) {
String type = context.getStringAttribute("type");
// awful patch to keep backward compatibility
if ("VENDOR".equals(type)) {
type = "DB_VENDOR";
}
Properties properties = context.getChildrenAsProperties();
databaseIdProvider = (DatabaseIdProvider) resolveClass(type).getDeclaredConstructor().newInstance();
databaseIdProvider.setProperties(properties);
}
Environment environment = configuration.getEnvironment();
if (environment != null && databaseIdProvider != null) {
String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
configuration.setDatabaseId(databaseId);
}
}
//事务处理的元素
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
TransactionFactory factory = (TransactionFactory) resolveClass(type).getDeclaredConstructor().newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}
//数据源处理的元素
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).getDeclaredConstructor().newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
//类型处理器的元素
private void typeHandlerElement(XNode parent) {
if (parent != null) {
for (XNode child : parent.getChildren()) {
if ("package".equals(child.getName())) {
String typeHandlerPackage = child.getStringAttribute("name");
typeHandlerRegistry.register(typeHandlerPackage);
} else {
String javaTypeName = child.getStringAttribute("javaType");
String jdbcTypeName = child.getStringAttribute("jdbcType");
String handlerTypeName = child.getStringAttribute("handler");
Class<?> javaTypeClass = resolveClass(javaTypeName);
JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
Class<?> typeHandlerClass = resolveClass(handlerTypeName);
if (javaTypeClass != null) {
if (jdbcType == null) {
typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
} else {
typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
}
} else {
typeHandlerRegistry.register(typeHandlerClass);
}
}
}
}
}
//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 {
String resource = child.getStringAttribute("resource");
String url = child.getStringAttribute("url");
String mapperClass = child.getStringAttribute("class");
if (resource != null && url == null && mapperClass == null) {
ErrorContext.instance().resource(resource);
InputStream inputStream = Resources.getResourceAsStream(resource);
XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
mapperParser.parse();
} else if (resource == null && url != null && mapperClass == null) {
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) {
Class<?> mapperInterface = Resources.classForName(mapperClass);
configuration.addMapper(mapperInterface);
} else {
throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
}
}
}
}
}
//是否指定环境
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;
}
}
3.3.4.2、XMLMapperBuilder源码分析
/**
* XML的mapper接口构建器
*/
public class XMLMapperBuilder extends BaseBuilder {
//解析器
private final XPathParser parser;
//接口助手
private final MapperBuilderAssistant builderAssistant;
//sql节点片段
private final Map<String, XNode> sqlFragments;
//资源
private final String resource;
//不建议使用,未来废弃
@Deprecated
public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
this(reader, configuration, resource, sqlFragments);
this.builderAssistant.setCurrentNamespace(namespace);
}
//不建议使用,未来废弃
@Deprecated
public XMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
this(new XPathParser(reader, true, configuration.getVariables(), new XMLMapperEntityResolver()),
configuration, resource, sqlFragments);
}
//构造函数
public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
this(inputStream, configuration, resource, sqlFragments);
this.builderAssistant.setCurrentNamespace(namespace);
}
//构造函数
public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
configuration, resource, sqlFragments);
}
//构造函数
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;
}
//解析mapper
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
//将mapper和命名空间绑定
bindMapperForNamespace();
}
//解析等待的结果映射
parsePendingResultMaps();
//解析等待的缓存引用
parsePendingCacheRefs();
//解析等待的会话
parsePendingStatements();
}
//获取sql片段根据引用ID
public XNode getSqlFragment(String refid) {
return sqlFragments.get(refid);
}
//配置全局配置
private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
//绑定当前的命名空间
builderAssistant.setCurrentNamespace(namespace);
//缓存引用
cacheRefElement(context.evalNode("cache-ref"));
//缓存
cacheElement(context.evalNode("cache"));
//参数map
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//结果map
resultMapElements(context.evalNodes("/mapper/resultMap"));
//sql
sqlElement(context.evalNodes("/mapper/sql"));
//会话语句
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
//构建会话从上下文
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
buildStatementFromContext(list, null);
}
//构建会话从上下文
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);
}
}
}
//解析等待的结果映射
private void parsePendingResultMaps() {
Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps();
synchronized (incompleteResultMaps) {
Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator();
while (iter.hasNext()) {
try {
iter.next().resolve();
iter.remove();
} catch (IncompleteElementException e) {
// ResultMap is still missing a resource...
}
}
}
}
//解析等待的缓存引用
private void parsePendingCacheRefs() {
Collection<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs();
synchronized (incompleteCacheRefs) {
Iterator<CacheRefResolver> iter = incompleteCacheRefs.iterator();
while (iter.hasNext()) {
try {
iter.next().resolveCacheRef();
iter.remove();
} catch (IncompleteElementException e) {
// Cache ref is still missing a resource...
}
}
}
}
//解析等待的会话
private void parsePendingStatements() {
Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements();
synchronized (incompleteStatements) {
Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator();
while (iter.hasNext()) {
try {
iter.next().parseStatementNode();
iter.remove();
} catch (IncompleteElementException e) {
// Statement is still missing a resource...
}
}
}
}
//缓存引用元素
private void cacheRefElement(XNode context) {
if (context != null) {
configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
try {
cacheRefResolver.resolveCacheRef();
} catch (IncompleteElementException e) {
configuration.addIncompleteCacheRef(cacheRefResolver);
}
}
}
//缓存元素
private void cacheElement(XNode context) {
if (context != null) {
String type = context.getStringAttribute("type", "PERPETUAL");
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
String eviction = context.getStringAttribute("eviction", "LRU");
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
Long flushInterval = context.getLongAttribute("flushInterval");
Integer size = context.getIntAttribute("size");
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
boolean blocking = context.getBooleanAttribute("blocking", false);
Properties props = context.getChildrenAsProperties();
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
}
}
//参数映射元素
private void parameterMapElement(List<XNode> list) {
for (XNode parameterMapNode : list) {
String id = parameterMapNode.getStringAttribute("id");
String type = parameterMapNode.getStringAttribute("type");
Class<?> parameterClass = resolveClass(type);
List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
List<ParameterMapping> parameterMappings = new ArrayList<>();
for (XNode parameterNode : parameterNodes) {
String property = parameterNode.getStringAttribute("property");
String javaType = parameterNode.getStringAttribute("javaType");
String jdbcType = parameterNode.getStringAttribute("jdbcType");
String resultMap = parameterNode.getStringAttribute("resultMap");
String mode = parameterNode.getStringAttribute("mode");
String typeHandler = parameterNode.getStringAttribute("typeHandler");
Integer numericScale = parameterNode.getIntAttribute("numericScale");
ParameterMode modeEnum = resolveParameterMode(mode);
Class<?> javaTypeClass = resolveClass(javaType);
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
parameterMappings.add(parameterMapping);
}
builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
}
}
//结果映射
private void resultMapElements(List<XNode> list) throws Exception {
for (XNode resultMapNode : list) {
try {
resultMapElement(resultMapNode);
} catch (IncompleteElementException e) {
// ignore, it will be retried
}
}
}
//结果映射
private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
return resultMapElement(resultMapNode, Collections.emptyList(), null);
}
//结果映射
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) throws Exception {
ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
String type = resultMapNode.getStringAttribute("type",
resultMapNode.getStringAttribute("ofType",
resultMapNode.getStringAttribute("resultType",
resultMapNode.getStringAttribute("javaType"))));
Class<?> typeClass = resolveClass(type);
if (typeClass == null) {
typeClass = inheritEnclosingType(resultMapNode, enclosingType);
}
Discriminator discriminator = null;
List<ResultMapping> resultMappings = new ArrayList<>();
resultMappings.addAll(additionalResultMappings);
List<XNode> resultChildren = resultMapNode.getChildren();
for (XNode resultChild : resultChildren) {
if ("constructor".equals(resultChild.getName())) {
processConstructorElement(resultChild, typeClass, resultMappings);
} else if ("discriminator".equals(resultChild.getName())) {
discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
} else {
List<ResultFlag> flags = new ArrayList<>();
if ("id".equals(resultChild.getName())) {
flags.add(ResultFlag.ID);
}
resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
}
}
String id = resultMapNode.getStringAttribute("id",
resultMapNode.getValueBasedIdentifier());
String extend = resultMapNode.getStringAttribute("extends");
Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
try {
return resultMapResolver.resolve();
} catch (IncompleteElementException e) {
configuration.addIncompleteResultMap(resultMapResolver);
throw e;
}
}
//继承封装类型
protected Class<?> inheritEnclosingType(XNode resultMapNode, Class<?> enclosingType) {
if ("association".equals(resultMapNode.getName()) && resultMapNode.getStringAttribute("resultMap") == null) {
String property = resultMapNode.getStringAttribute("property");
if (property != null && enclosingType != null) {
MetaClass metaResultType = MetaClass.forClass(enclosingType, configuration.getReflectorFactory());
return metaResultType.getSetterType(property);
}
} else if ("case".equals(resultMapNode.getName()) && resultMapNode.getStringAttribute("resultMap") == null) {
return enclosingType;
}
return null;
}
//执行构造元素
private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
List<XNode> argChildren = resultChild.getChildren();
for (XNode argChild : argChildren) {
List<ResultFlag> flags = new ArrayList<>();
flags.add(ResultFlag.CONSTRUCTOR);
if ("idArg".equals(argChild.getName())) {
flags.add(ResultFlag.ID);
}
resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags));
}
}
//执行鉴别器元素
private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
String column = context.getStringAttribute("column");
String javaType = context.getStringAttribute("javaType");
String jdbcType = context.getStringAttribute("jdbcType");
String typeHandler = context.getStringAttribute("typeHandler");
Class<?> javaTypeClass = resolveClass(javaType);
Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
Map<String, String> discriminatorMap = new HashMap<>();
for (XNode caseChild : context.getChildren()) {
String value = caseChild.getStringAttribute("value");
String resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings, resultType));
discriminatorMap.put(value, resultMap);
}
return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
}
//sql元素
private void sqlElement(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
sqlElement(list, configuration.getDatabaseId());
}
sqlElement(list, null);
}
//sql元素
private void sqlElement(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
String databaseId = context.getStringAttribute("databaseId");
String id = context.getStringAttribute("id");
id = builderAssistant.applyCurrentNamespace(id, false);
if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
sqlFragments.put(id, context);
}
}
}
//数据库ID匹配当前要求
private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
if (requiredDatabaseId != null) {
return requiredDatabaseId.equals(databaseId);
}
if (databaseId != null) {
return false;
}
if (!this.sqlFragments.containsKey(id)) {
return true;
}
// skip this fragment if there is a previous one with a not null databaseId
XNode context = this.sqlFragments.get(id);
return context.getStringAttribute("databaseId") == null;
}
//从上下文构建结果映射
private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) throws Exception {
String property;
if (flags.contains(ResultFlag.CONSTRUCTOR)) {
property = context.getStringAttribute("name");
} else {
property = context.getStringAttribute("property");
}
String column = context.getStringAttribute("column");
String javaType = context.getStringAttribute("javaType");
String jdbcType = context.getStringAttribute("jdbcType");
String nestedSelect = context.getStringAttribute("select");
String nestedResultMap = context.getStringAttribute("resultMap",
processNestedResultMappings(context, Collections.emptyList(), resultType));
String notNullColumn = context.getStringAttribute("notNullColumn");
String columnPrefix = context.getStringAttribute("columnPrefix");
String typeHandler = context.getStringAttribute("typeHandler");
String resultSet = context.getStringAttribute("resultSet");
String foreignColumn = context.getStringAttribute("foreignColumn");
boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
Class<?> javaTypeClass = resolveClass(javaType);
Class<? extends TypeHandler<?>> typeHandlerClass = resolveClass(typeHandler);
JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);
}
//执行嵌套结果映射
private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings, Class<?> enclosingType) throws Exception {
if ("association".equals(context.getName())
|| "collection".equals(context.getName())
|| "case".equals(context.getName())) {
if (context.getStringAttribute("select") == null) {
validateCollection(context, enclosingType);
ResultMap resultMap = resultMapElement(context, resultMappings, enclosingType);
return resultMap.getId();
}
}
return null;
}
//校验集合
protected void validateCollection(XNode context, Class<?> enclosingType) {
if ("collection".equals(context.getName()) && context.getStringAttribute("resultMap") == null
&& context.getStringAttribute("javaType") == null) {
MetaClass metaResultType = MetaClass.forClass(enclosingType, configuration.getReflectorFactory());
String property = context.getStringAttribute("property");
if (!metaResultType.hasSetter(property)) {
throw new BuilderException(
"Ambiguous collection type for property '" + property + "'. You must specify 'javaType' or 'resultMap'.");
}
}
}
//构建命名空间的mapper
private void bindMapperForNamespace() {
String namespace = builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class<?> boundType = null;
try {
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException e) {
//ignore, bound type is not required
}
if (boundType != null) {
if (!configuration.hasMapper(boundType)) {
configuration.addLoadedResource("namespace:" + namespace);
configuration.addMapper(boundType);
}
}
}
}
}
Mybatis构建加载初始化源码分析这节到这里就结束了,可以再回顾下核心重点图。