mybatis核心处理层-初始化
初始化主要依靠读取mybatis配置文件mybatis-config.xml 或者通过注解进行包扫描的方式,进行对象的注入
一、建造者模式-生成器模式
将一个复杂对象的构建过程与他的表示分离。一个复杂对象的构建也可以拆成若干简单步骤,用户指出了解对象类型和内容,不需要关注内部复杂的构造过程
1. 角色
- 建造者(Builder):Builder 接口用于定义建造者构建产品对象的各部分的行为
- 具体建造者(Concrete Builder): 直接创建产品对象的是具体建造者,包含建造方法,和获取对象的方法
- 导演(Director): 该角色会通过调用具体建造者,创建需要的产品对象
-
产品 (Product): 产品对象就需要建造的复杂对象
- 建造者模式优点:
- 导演不需要知道产品的内部细节,提供信息,让建造者完成建造
- 将复杂产品的创造过程分散到不同的构造步骤中,实现对产品创建过程的精准控制,使过程更加清晰
- 具体建造者之间相互独立,不同产品可以构建不同的建造者,不会影响代码稳定性,符合开放-封闭原则
- 建造者模式缺点:
- 不适合差异性大的产品,如果产品种类交过,内部变化复杂,则会增加系统的复杂性
2.mybatis中的运用
- BaseBuilder
二、 BaseBuilder
mybatis初始化入口SqlSessionFactoryBuilder,构建了SqlSessionFactory,就有后续的初始化步骤
- SqlSessionFactoryBuilder,内部各种build方法,接受不同参数,达到建造SqlSessionFactory的目的
- 通过Reader或者InputStream的方式获取mybatis-config.xml文件
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
//xml的读取和参数映射,设置Configuratio对象,在mybatis中承载大部分基础配置参数
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.
}
}
}
1.BaseBuilder 建造者
- 上面的XMLConfigBuilder就是baseBuilder的实现类,这边的BaseBuilder就是建造者
//BaseBuilder基础属性
//初始化过程核心对象 almost all in one
protected final Configuration configuration;
//配置中<typeAliases>标签定义别名
protected final TypeAliasRegistry typeAliasRegistry;
//配置中<typeHanlders>标签定义的已定义类型处理器
protected final TypeHandlerRegistry typeHandlerRegistry;
三.XMLConfigBuilder 具体建造者
主要负责解析mybatis-config.xml 初始化Configuration
1.parse方法作为入口
//入口
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
//修改parse标志位
parsed = true;
//节点查找 evalNode <configuration> 并解析
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
//解析<properties>
propertiesElement(root.evalNode("properties"));
//解析<settings>
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
loadCustomLogImpl(settings);
//解析<typeAliases>
typeAliasesElement(root.evalNode("typeAliases"));
//解析<plugins>
pluginElement(root.evalNode("plugins"));
//解析<objectFactory>
objectFactoryElement(root.evalNode("objectFactory"));
//解析<objectWrapperFactory>
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
// 解析<reflectorFactory>
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
//解析<environments>
environmentsElement(root.evalNode("environments"));
//解析<databaseIdProvider>
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//解析<typeHandlers>
typeHandlerElement(root.evalNode("typeHandlers"));
//解析<mappers>
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
2.properties
private void propertiesElement(XNode context) throws Exception {
if (context != null) {
//记录properties标签的Name 和value 记录到 Properties对象中
Properties defaults = context.getChildrenAsProperties();
String resource = context.getStringAttribute("resource");
String url = context.getStringAttribute("url");
//resource 和 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);
}
}
3.settings
private Properties settingsAsProperties(XNode context) {
if (context == null) {
return new Properties();
}
//读取settings 标签中的
Properties props = context.getChildrenAsProperties();
// Check that all settings are known to the configuration class
//获取class的元信息 metaConfig
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;
}
4.typeAliases
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 {
//指定类
//xnode解析xml文档,前面有涉及过,以string读取内容
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);
}
}
}
}
}
5.plugins
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);
}
}
}
6.objectFactory
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);
}
}
7.objectWrapperFactory 与objectFactory相似
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);
}
}
8.reflectorFactory 与objectFactory相似
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);
}
}
9.environments
//不同环境的environments --> environment
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
//未指定environment 使用default
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对象
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
10.databaseIdProvider
DatabaseIdProvider接口有两个实现类:VendorDatabaseIdProvider & DefaultDatabaseIdProvider(过期)
//通过databaseId区分多种数据库产品在SQL语言支持方面的差距,在初始化的时候确定使用数据库产品,再进行相应的解析,在家带databaseId和不带databaseId的SQL语句,如果SQL相同,带databaseId的权重大将被使用
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
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) {
//databaseId绑定数据库
String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
configuration.setDatabaseId(databaseId);
}
}
11.typeHandlers
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 {
//指定Java类型和jdbc类型的处理类
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);
}
}
}
}
}
12.mappers
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);
//加载resource,构建XMLMapperBuilder
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);
//加载url ,加载XMLMapperBuilder
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.");
}
}
}
}
}
四.XMLMapperBuilder 具体建造者
- 由于继承自baseBuilder,那么核心入口就看parse
public void parse() {
if (!configuration.isResourceLoaded(resource)) {
//尚未加载资源,基础mapper
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
bindMapperForNamespace();
}
//处理configurationElement里解析失败的resultMap节点
parsePendingResultMaps();
//处理configurationElement里解析失败的cacheRef节点
parsePendingCacheRefs();
//处理configurationElement里解析失败的SQL语句节点
parsePendingStatements();
}
public XNode getSqlFragment(String refid) {
return sqlFragments.get(refid);
}
//下面就很熟悉,使用各种方法加载不同的节点
private void configurationElement(XNode context) {
try {
//获取namespace属性
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.isEmpty()) {
//如果为空异常
throw new BuilderException("Mapper's namespace cannot be empty");
}
builderAssistant.setCurrentNamespace(namespace);
//解析cacheref
cacheRefElement(context.evalNode("cache-ref"));
//解析cache
cacheElement(context.evalNode("cache"));
//解析paramMap 已废弃
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
//解析resultMap
resultMapElements(context.evalNodes("/mapper/resultMap"));
//解析sql语句 <sql>
sqlElement(context.evalNodes("/mapper/sql"));
//解析 <select> <delete> <update> <insert>
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);
}
}
1. cache 节点,mybatis有一级二级缓存,二级缓存默认是不开启的
//XMLMapperBuilder
private void cacheElement(XNode context) {
if (context != null) {
//获取cache的实现类 ,默认值PERPETUAL(前面有讲到唯一的实现)
String type = context.getStringAttribute("type", "PERPETUAL");
//找到type属性对应的cache
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
//获取cache的eviction属性,默认LRU策略
String eviction = context.getStringAttribute("eviction", "LRU");
//找到对应eviction属性的cache装饰器类,LRUCache
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
//获取 flushInterval属性,默认为null ,对应装饰类SchedulingCache
Long flushInterval = context.getLongAttribute("flushInterval");
//获取cache节点的size属性,默认null
Integer size = context.getIntAttribute("size");
//获取cache节点readOnly属性,默认false
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
//获取cache节点 blocking属性 对应装饰类 BlockingCache
boolean blocking = context.getBooleanAttribute("blocking", false);
Properties props = context.getChildrenAsProperties();
// 通过以上属性 创建cache对象 并添加到Configuration.cache集合中
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
}
}
//最后的MapperBuilderAssistant builderAssistant 是一个辅助类
//useNewCache 创建新的cache对象,并将其添加到configuration.caches的列表中
// MapperBuilderAssistant
public Cache useNewCache(Class<? extends Cache> typeClass,
Class<? extends Cache> evictionClass,
Long flushInterval,
Integer size,
boolean readWrite,
boolean blocking,
Properties props) {
//创建新的cache对象
Cache cache = new CacheBuilder(currentNamespace)
.implementation(valueOrDefault(typeClass, PerpetualCache.class))
.addDecorator(valueOrDefault(evictionClass, LruCache.class))
.clearInterval(flushInterval)
.size(size)
.readWrite(readWrite)
.blocking(blocking)
.properties(props)
.build();
//添加到configuration的caches中
configuration.addCache(cache);
currentCache = cache;
return cache;
}
//Configuration
protected final Map<String, Cache> caches = new StrictMap<>("Caches collection");
//StrictMap 是Configuration的一个内部类,继承自HashMap对其实现了一些改变,主要在于get和put的时候
public V put(String key, V value) {
if (containsKey(key)) {
throw new IllegalArgumentException(name + " already contains value for " + key
+ (conflictMessageProducer == null ? "" : conflictMessageProducer.apply(super.get(key), value)));
}
//区别在于,这边会对key做一个简短的处理,获取shortname
if (key.contains(".")) {
final String shortKey = getShortName(key);
if (super.get(shortKey) == null) {
//不存在直接添加
super.put(shortKey, value);
} else {
//存在,添加为Ambiguity对象后添加
super.put(shortKey, (V) new Ambiguity(shortKey));
}
}
return super.put(key, value);
}
@Override
public V get(Object key) {
V value = super.get(key);
if (value == null) {
throw new IllegalArgumentException(name + " does not contain value for " + key);
}
if (value instanceof Ambiguity) {
//如果是Ambiguity类型,证明key出现过重复情况,抛出异常
throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
+ " (try using the full name including the namespace, or rename one of the entries)");
}
return value;
}
2.CacheBuilder 采用建造者模式 构造Cache对象
public Cache build() {
setDefaultImplementations();
//根据实现类和id构造Cache实例 ,通过构造方法创建实例
Cache cache = newBaseCacheInstance(implementation, id);
setCacheProperties(cache);
// issue #352, do not apply decorators to custom caches
if (PerpetualCache.class.equals(cache.getClass())) {
//是PerpetualCache实现类,为其添加装饰器cache类
for (Class<? extends Cache> decorator : decorators) {
//通过构造方法创建装饰器cache实例
cache = newCacheDecoratorInstance(decorator, cache);
//设置参数
setCacheProperties(cache);
}
//设置标准装饰器
cache = setStandardDecorators(cache);
} else if (!LoggingCache.class.isAssignableFrom(cache.getClass())) {
//不是LoggingCache的子类,就直接创建一个LoggingCache
cache = new LoggingCache(cache);
}
return cache;
}
private Cache setStandardDecorators(Cache cache) {
try {
MetaObject metaCache = SystemMetaObject.forObject(cache);
if (size != null && metaCache.hasSetter("size")) {
metaCache.setValue("size", size);
}
if (clearInterval != null) {
cache = new ScheduledCache(cache);
((ScheduledCache) cache).setClearInterval(clearInterval);
}
if (readWrite) {
cache = new SerializedCache(cache);
}
//默认添加
cache = new LoggingCache(cache);
//默认添加
cache = new SynchronizedCache(cache);
if (blocking) {
cache = new BlockingCache(cache);
}
return cache;
} catch (Exception e) {
throw new CacheException("Error building standard cache decorators. Cause: " + e, e);
}
}
3.解析 cacheref 节点
//解析cache-ref节点
private void cacheRefElement(XNode context) {
if (context != null) {
//将namespace2和namespace1绑定,存入configuration protected final Map<String, String> cacheRefMap = new HashMap<>();
configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
//创建cacheRefResolver
CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
try {
//解析cache 引用,最终依靠MapperBuilderAssistant辅助类
//设置currentCache = cache;
//设置unresolvedCacheRef = false;
cacheRefResolver.resolveCacheRef();
} catch (IncompleteElementException e) {
configuration.addIncompleteCacheRef(cacheRefResolver);
}
}
}
//configuration
public void addCacheRef(String namespace, String referencedNamespace) {
cacheRefMap.put(namespace, referencedNamespace);
}
//MapperBuilderAssistant
public Cache useCacheRef(String namespace) {
if (namespace == null) {
throw new BuilderException("cache-ref element requires a namespace attribute.");
}
try {
unresolvedCacheRef = true;
Cache cache = configuration.getCache(namespace);
if (cache == null) {
throw new IncompleteElementException("No cache for namespace '" + namespace + "' could be found.");
}
currentCache = cache;
unresolvedCacheRef = false;
return cache;
} catch (IllegalArgumentException e) {
throw new IncompleteElementException("No cache for namespace '" + namespace + "' could be found.", e);
}
}
4. 解析resultMap节点
通常一个resultMap体中都有很多行,javatype和jdbctype的映射关系,会被映射为ResultMapping
//内部属性
private Configuration configuration;
//节点property属性
private String property;
//节点column属性
private String column;
//对应节点的javaType属性,可能是java类名,或者一个类型的别名
private Class<?> javaType;
//jdbc类型
private JdbcType jdbcType;
//类型处理器
private TypeHandler<?> typeHandler;
private String nestedResultMapId;
private String nestedQueryId;
private Set<String> notNullColumns;
private String columnPrefix;
//处理后的标志,共两个,id constructor
private List<ResultFlag> flags;
//对应节点的column属性拆分后生成的结果
private List<ResultMapping> composites;
//resultSet属性
private String resultSet;
private String foreignColumn;
//是否延迟加载
private boolean lazy;
//通过建造者模式设置以上参数 内部类Builder
多个resultMappings形成一个resultMap
//resultmap
private Configuration configuration;
//resultMap节点id属性
private String id;
//resultmap节点type属性
private Class<?> type;
//多个字段的映射关系
private List<ResultMapping> resultMappings;
//记录带有ID标志的映射关系
private List<ResultMapping> idResultMappings;
//记录带有constructor标志的映射关系
private List<ResultMapping> constructorResultMappings;
//记录不带有constructor的映射关系
private List<ResultMapping> propertyResultMappings;
//记录所有映射关系中设计的column属性的集合
private Set<String> mappedColumns;
//
private Set<String> mappedProperties;
//对应 discriminator节点
private Discriminator discriminator;
//存在resultmap 不存在resultset
private boolean hasNestedResultMaps;
//是否含有嵌套查询
private boolean hasNestedQueries;
//是否开启自动映射
private Boolean autoMapping;
resultMap也通过建造者模式Builder的形式初始化以上属性 ResultMapping 内部有一个Builder类,采用建造者模式,实现数据整理和数据校验 XMLMapperBuilder 中处理resultMap节点
//处理resultMap节点
private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings, Class<?> enclosingType) {
ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
//获取type属性
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<>(additionalResultMappings);
List<XNode> resultChildren = resultMapNode.getChildren();
//遍历子节点
for (XNode resultChild : resultChildren) {
//节点是 constructor 类型
if ("constructor".equals(resultChild.getName())) {
processConstructorElement(resultChild, typeClass, resultMappings);
} else if ("discriminator".equals(resultChild.getName())) {
//节点是discriminator类型
discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
} else {
//处理id result association collection
List<ResultFlag> flags = new ArrayList<>();
if ("id".equals(resultChild.getName())) {
//如果是ID,向集合中添加ResultFlag.ID
flags.add(ResultFlag.ID);
}
//创建resultMapping对象,并添加到resultMappings集合中保存
resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
}
}
//id属性
String id = resultMapNode.getStringAttribute("id",
resultMapNode.getValueBasedIdentifier());
//extends属性
String extend = resultMapNode.getStringAttribute("extends");
//是否自动映射,如果true则开启自动映射功能,自动查找
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;
}
}
private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) {
String property;
//包含constructor
if (flags.contains(ResultFlag.CONSTRUCTOR)) {
//name属性 -> property
property = context.getStringAttribute("name");
} else {
//property属性
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);
//构建resultMapping对象
return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);
}
resultMap解析,包括解析constructor节点、association collection case 节点、discriminator节点
5.解析sql节点
五.XMLStatementBuilder 具体建造者
- SqlSource 数据源 : DynamicSqlSource/ProviderSqlSource/RawSqlSource/StaticSqlSource
- 解析SQL节点的入口
public void parseStatementNode() {
//获取id
String id = context.getStringAttribute("id");
//获取databaseId
String databaseId = context.getStringAttribute("databaseId");
//如果 databaseId 与当前使用类型不匹配,就不解析
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
//获取多种查询属性配置
String nodeName = context.getNode().getNodeName();
//SQL类型
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
//解析<include>节点
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
String parameterType = context.getStringAttribute("parameterType");
Class<?> parameterTypeClass = resolveClass(parameterType);
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
// Parse selectKey after includes and remove them.
//解析<selectkey>节点
processSelectKeyNodes(id, parameterTypeClass, langDriver);
// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
//检测sql中是否配置了selectkey ,sql节点的useGeneratedKeys 属性值
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;
}
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String resultType = context.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
String resultMap = context.getStringAttribute("resultMap");
String resultSetType = context.getStringAttribute("resultSetType");
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
if (resultSetTypeEnum == null) {
resultSetTypeEnum = configuration.getDefaultResultSetType();
}
//获取 keyProperty keyColumn resultSets
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
String resultSets = context.getStringAttribute("resultSets");
//创建MappedStatement 并添加到mapped statements集合中
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
1.解析 include 节点
//入口
public void applyIncludes(Node source) {
Properties variablesContext = new Properties();
Properties configurationVariables = configuration.getVariables();
Optional.ofNullable(configurationVariables).ifPresent(variablesContext::putAll);
applyIncludes(source, variablesContext, false);
}
/**
* Recursively apply includes through all SQL fragments.
*
* @param source
* Include node in DOM tree
* @param variablesContext
* Current context for static variables with values
* 递归调用,替换include中的SQL片段,并且将占位符替换成真正的参数
*/
private void applyIncludes(Node source, final Properties variablesContext, boolean included) {
if (source.getNodeName().equals("include")) {
//获取refid对应指向的SQL片段 , 返回深克隆的Node对象
Node toInclude = findSqlFragment(getStringAttribute(source, "refid"), variablesContext);
//将解析到的参数键值添加到variablesContext中,用于替换
Properties toIncludeContext = getVariablesContext(source, variablesContext);
//递归处理include标签,内部sql节点可能会使用include继续应用其他SQL
applyIncludes(toInclude, toIncludeContext, true);
if (toInclude.getOwnerDocument() != source.getOwnerDocument()) {
toInclude = source.getOwnerDocument().importNode(toInclude, true);
}
//将获取的SQL节点替换include节点
source.getParentNode().replaceChild(toInclude, source);
while (toInclude.hasChildNodes()) {
//将内部的子SQL频段添加到SQL前面
toInclude.getParentNode().insertBefore(toInclude.getFirstChild(), toInclude);
}
//删除SQL节点
toInclude.getParentNode().removeChild(toInclude);
} else if (source.getNodeType() == Node.ELEMENT_NODE) {
if (included && !variablesContext.isEmpty()) {
// replace variables in attribute values
NamedNodeMap attributes = source.getAttributes();
//遍历子节点
for (int i = 0; i < attributes.getLength(); i++) {
Node attr = attributes.item(i);
//使用之前解析到的参数替换占位符
attr.setNodeValue(PropertyParser.parse(attr.getNodeValue(), variablesContext));
}
}
NodeList children = source.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
applyIncludes(children.item(i), variablesContext, included);
}
} else if (included && (source.getNodeType() == Node.TEXT_NODE || source.getNodeType() == Node.CDATA_SECTION_NODE)
&& !variablesContext.isEmpty()) {
// replace variables in text node
source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
}
}
2.解析selectKey 节点
private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
List<XNode> selectKeyNodes = context.evalNodes("selectKey");
if (configuration.getDatabaseId() != null) {
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
}
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
removeSelectKeyNodes(selectKeyNodes);
}
private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
for (XNode nodeToHandle : list) {
String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
String databaseId = nodeToHandle.getStringAttribute("databaseId");
if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
}
}
}
private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
//获取 resultType statementType keyProperty keyColumn order 等属性
String resultType = nodeToHandle.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));
// defaults
boolean useCache = false;
boolean resultOrdered = false;
KeyGenerator keyGenerator = NoKeyGenerator.INSTANCE;
Integer fetchSize = null;
Integer timeout = null;
boolean flushCache = false;
String parameterMap = null;
String resultMap = null;
ResultSetType resultSetTypeEnum = null;
//通过languageDriver创建SQLSOURCE
// languageDriver 可以通过mybatis-config.xml进行配置,也可以自定义实现,可以由defaultScriptingLanguage指定
//languageDriver 有两个实现类: XMLLanguageDriver RawLanguageDriver
SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);
//<selectKey 里面只能配置SELECT语句
SqlCommandType sqlCommandType = SqlCommandType.SELECT;
//通过辅助类创建mappedStatement,并添加到mappedstatements集合中 ,类型是StrictMap
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null);
id = builderAssistant.applyCurrentNamespace(id, false);
MappedStatement keyStatement = configuration.getMappedStatement(id, false);
//床建select key 节点对应的key generator 添加到Configuration的key generators集合中,类型也是StrictMap
configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
}