解析 typeAliases

在 XMLConfigBuilder 当中的 parseConfiguration 方法当中 typeAliasesElement(root.evalNode(“typeAliases”)); 来解析 typeAliases,下面是详细代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
}
}
}
}
}

对应的 xml 格式如下:

1
2
3
4
5
<typeAliases>
<package name="com.rcx.test"/>
<typeAlias type="com.rcx.User" alias="User"/>
<typeAlias type="com.rcx.Book" />
</typeAliases>

当是 package 的时候把这个包下面的所有类都扫描出来当成别名。下面的两种方式是指定具体的 class,区别就是指定了别名,和没指定别名,没指定别名的时候使用 class.getSimpleName(); 来当作别名。

下面看一下 TypeAliasRegistry 的内部数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
public class TypeAliasRegistry {

private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();

public TypeAliasRegistry() {
registerAlias("string", String.class);
...省略了内置的基本类似别名
registerAlias("iterator", Iterator.class);

}

}

结构很简单,里面就是一个 HashMap 然后对这个 map 进行各种操作。

BaseBuilder

上面提到的 XMLConfigBuilder 继承于 BaseBuilder,而且其他所有解析 XML 的 Builder 都会继承这个抽象类。

看下 BaseBuilder 当中的结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
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();
}

...其他方法先省略
}

当创建 BaseBuilder 子类实例的时候,需要传入 Configuration 的实例,入口的解析器 Builder 就是 XMLConfigBuilder,看下它的构造方法:

1
2
3
4
5
6
7
8
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;
}

因为在 SqlSessionFactoryBuilder 类当中 build 生成 SqlSessionFactory 的时候是调用了 XMLConfigBuilder 的 parse 方法生成 Configuration 实例,代码如下:

1
2
3
4
5
6
7
8
9
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
//省略了 try 和 catch
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
}

public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}

所以初始化 Configuration 实例的流程就清晰了:

  1. 先创建 XMLConfigBuilder 实例,然后创建了 Configuration 实例
  2. 在 XMLConfigBuilder 当中把 Configuration 的每一个节点都解析然后设置进去
  3. 最后返回 Configuration 实例,完成初始化工作

当然 BaseBuilder 当中还包含了解析 Builder 的一些通用的工具方法,下面简单列几个:

1
2
3
4
5
6
7
8
9
10
11
protected Pattern parseExpression(String regex, String defaultValue) {
return Pattern.compile(regex == null ? defaultValue : regex);
}

protected Boolean booleanValueOf(String value, Boolean defaultValue) {
return value == null ? defaultValue : Boolean.valueOf(value);
}

protected Integer integerValueOf(String value, Integer defaultValue) {
return value == null ? defaultValue : Integer.valueOf(value);
}

XMLConfigBuilder 的具体工作

要想了解 XMLConfigBuilder 的具体工作就要看它的 parseConfiguration 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));//解析内置的属性
typeAliasesElement(root.evalNode("typeAliases"));//解析别名
pluginElement(root.evalNode("plugins"));//解析插件
objectFactoryElement(root.evalNode("objectFactory"));//解析对象工厂
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectionFactoryElement(root.evalNode("reflectionFactory"));
settingsElement(root.evalNode("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"));//解析用户定义的 mappers
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}

从上面可以看出来,主要是对 config.xml 进行解析,刚才分析了别名的解析比较简单,比较复杂的是 mappers 的解析。

下面挑一些进行简单分析解析插件

1
2
3
4
5
6
7
8
9
10
11
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).newInstance();
interceptorInstance.setProperties(properties);
configuration.addInterceptor(interceptorInstance);
}
}
}

对应的 xml 如下:

1
2
3
4
5
6
<plugins>
<plugin interceptor="com.rcx.TestInterceptor">
<property name="" value=""/>
<property name="" value=""/>
</plugin>
</plugins>

不需要过多的解释,主要看 configuration.addInterceptor(interceptorInstance); 在 configuration 当中的数据结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected final InterceptorChain interceptorChain = new InterceptorChain();

public void addInterceptor(Interceptor interceptor) {
interceptorChain.addInterceptor(interceptor);
}

public class InterceptorChain {

private final List<Interceptor> interceptors = new ArrayList<Interceptor>();

public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}

public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}

public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
}

}

数据结构也很明了,在 List 当中按顺序存放所有的插件。

解析 typeHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void typeHandlerElement(XNode parent) throws Exception {
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);
}
}
}
}
}

对应的 XML 如下:

1
2
3
4
<typeHandlers>
<package name="com.rcx.test"/>
<typeHandler handler="" javaType="" jdbcType=""/>
</typeHandlers>

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。

package 是在这个包下的都扫描成 typeHandler,typeHandler 标签的具体分析,下面看 typeHandlerRegistry 的数据结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 在 Configuration 当中的属性
protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();

public final class TypeHandlerRegistry {

private final Map<JdbcType, TypeHandler<?>> JDBC_TYPE_HANDLER_MAP = new EnumMap<JdbcType, TypeHandler<?>>(JdbcType.class);
private final Map<Type, Map<JdbcType, TypeHandler<?>>> TYPE_HANDLER_MAP = new HashMap<Type, Map<JdbcType, TypeHandler<?>>>();
private final TypeHandler<Object> UNKNOWN_TYPE_HANDLER = new UnknownTypeHandler(this);
private final Map<Class<?>, TypeHandler<?>> ALL_TYPE_HANDLERS_MAP = new HashMap<Class<?>, TypeHandler<?>>();

public TypeHandlerRegistry() {
register(Boolean.class, new BooleanTypeHandler());
...//省略
register(char.class, new CharacterTypeHandler());
}

}

JDBC_TYPE_HANDLER_MAP 这个 map 存放的是 JDBC 类型的 TypeHandler 在 TypeHandlerRegistry 构造方法里面已经进行了初始化:

1
2
3
4
5
public TypeHandlerRegistry() {
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
。。。省略
}

之所以创建的是 EnumMap 是因为数据库类型一定小于 64 种,使用 EnumMap 会更快、也节省空间。

TYPE_HANDLER_MAP 最个 map 是存放我们自定义的类型的转换的 map,我们自定义的 TypeHandler 都要继承于 BaseTypeHandler 这个类,BaseTypeHandler 继承于 TypeReference,继承于 TypeReference 的主要作用就是可通过反射拿到具体的 TypeHandler 的泛型 class。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public abstract class TypeReference<T> {

private final Type rawType;

protected TypeReference() {
rawType = getSuperclassTypeParameter(getClass());
}

Type getSuperclassTypeParameter(Class<?> clazz) {
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof Class) {
// try to climb up the hierarchy until meet something useful
if (TypeReference.class != genericSuperclass) {
return getSuperclassTypeParameter(clazz.getSuperclass());
}

throw new TypeException("'" + getClass() + "' extends TypeReference but misses the type parameter. "
+ "Remove the extension or add a type parameter to it.");
}

Type rawType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
// TODO remove this when Reflector is fixed to return Types
if (rawType instanceof ParameterizedType) {
rawType = ((ParameterizedType) rawType).getRawType();
}

return rawType;
}

public final Type getRawType() {
return rawType;
}

@Override
public String toString() {
return rawType.toString();
}

}

所以 TYPE_HANDLER_MAP 的 key 是 Type 类型,但是他的 value 是一个 Map<JdbcType, TypeHandler<?>> map,看起来很奇怪但是仔细想想很合理,有多个 jdbc 类型可以转换成相同的 java 类型,那么有可能就需要不同的 TypeHandler。

ALL_TYPE_HANDLERS_MAP 就是存放所有的 typeHandler

TypeHandlerRegistry 类当中的重载的 register 就不仔细分析了。

—EOF—