双篇同线进行 mybatis-config.xml 文件的解析。本篇的目的就是深入函数解析。XNode 是 xml 的标签解析得到的存储属性、子节点的信息类。
- 各子节点对应的源码在 Mybatis 的脉络梳理01之解析mybatis-config.xml 查看。这里只展示部分方法源码。
1. properties
- propertiesElement(root.evalNode(“properties”))
1.1 context.getChildrenAsProperties()
/* 循环遍历子节点,获取 name,value 值,生成键值对并返回 */
public Properties getChildrenAsProperties() {
Properties properties = new Properties();
for (XNode child : getChildren()) {
String name = child.getStringAttribute("name");
String value = child.getStringAttribute("value");
if (name != null && value != null) {
properties.setProperty(name, value);
}
}
return properties;
}
1.2 context.getStringAttribute(“XXX”)
/* name: 属性名称,def: 指定属性默认值,未指定则未 null */
public String getStringAttribute(String name) {
return getStringAttribute(name, null);
}
public String getStringAttribute(String name, String def) {
String value = attributes.getProperty(name);
if (value == null) {
return def;
} else {
return value;
}
}
1.3 Resources.getResourceAsProperties(resource)
- 获取 resource 指定的资源文件,然后通过 Properties 读取
- Resources 类的函数
/* 使用了1.8的特性之 try-with-resources */
public static Properties getResourceAsProperties(String resource) throws IOException {
Properties props = new Properties();
try (InputStream in = getResourceAsStream(resource)) {
props.load(in);
}
return props;
}
- getResourceAsStream():底层使用 ClassLoader 加载资源
/* 重载函数作用,指定没有传入的参数为 null */
public static InputStream getResourceAsStream(String resource) throws IOException {
return getResourceAsStream(null, resource);
}
/* 通过 class加载器 与 resource 获取输入流 */
public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException {
InputStream in = classLoaderWrapper.getResourceAsStream(resource, loader);
if (in == null) {
throw new IOException("Could not find resource " + resource);
}
return in;
}
- ClassLoaderWrapper 类的函数
public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
return getResourceAsStream(resource, getClassLoaders(classLoader));
}
/* 真正获取资源的方法 */
/*
* 1. 循环类加载器数组classLoader
* 2. 判断类加载器cl是否为null,若不为null则通过resource路径加载资源
* 3. 由于某些类加载器可能需要路径以"/"开头,若returnValue 为null则添加"/"并再次尝试
* 4. 若 returnValue 不为null则将其返回,否则继续循环,直接结束还未找到则返回 null
*/
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
for (ClassLoader cl : classLoader) {
if (null != cl) {
InputStream returnValue = cl.getResourceAsStream(resource);
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}
if (null != returnValue) {
return returnValue;
}
}
}
return null;
}
- getClassLoaders(classLoader):获取类加载器的数组
/*
* classLoader:传入的类加载器
* defaultClassLoader:默认类加载器
* Thread.currentThread().getContextClassLoader(): 当前线程的 context 类加载器
* getClass().getClassLoader():当前类的类加载器
* systemClassLoader:系统类加载器
*/
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader,
defaultClassLoader,
Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(),
systemClassLoader};
}
1.4 getUrlAsStream()
- 获取连接通道,从这也可看出 url 是获取网络资源 or 本地系统的文件
public static InputStream getUrlAsStream(String urlString) throws IOException {
URLurl = new URL(urlString);
URLConnection conn = url.openConnection();
return conn.getInputStream();
}
2. settings
2.1 MetaClass.forClass()
- 首先来看 MetaClass 类
/* reflectorFactory: 反射工厂, reflector: 用于存储类信息 */
public class MetaClass {
private final ReflectorFactory reflectorFactory;
private final Reflector reflector;
}
- 先细看 ReflectorFactory 接口及其默认实现类
/* 接口,定义了三个抽象方法 */
public interface ReflectorFactory {
boolean isClassCacheEnabled();
void setClassCacheEnabled(boolean classCacheEnabled);
Reflector findForClass(Class<?> type);
}
/* ReflectorFactory 的默认实现类,后面需要用到 */
public class DefaultReflectorFactory implements ReflectorFactory {
private boolean classCacheEnabled = true;
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
public DefaultReflectorFactory() {
}
@Override
public boolean isClassCacheEnabled() {
return classCacheEnabled;
}
@Override
public void setClassCacheEnabled(boolean classCacheEnabled) {
this.classCacheEnabled = classCacheEnabled;
}
/* 若使用缓存(默认开启),则从reflectorMap获取
* computeIfAbsent():存在则获取,不存在则 new 一个放进去
* jdk1.8新增,Reflector::new <==> new Reflector(),但这里有参数,实际上调用的是 new Reflector(type)
* */
@Override
public Reflector findForClass(Class<?> type) {
if (classCacheEnabled) {
return reflectorMap.computeIfAbsent(type, Reflector::new);
} else {
return new Reflector(type);
}
}
}
- 再看 Reflector 类
public class Reflector {
/* class 类型 */
private final Class<?> type;
/* 可读属性数组 */
private final String[] readablePropertyNames;
/* 可写属性数组 */
private final String[] writablePropertyNames;
/* set方法集合 */
private final Map<String, Invoker> setMethods = new HashMap<>();
/* get方法集合 */
private final Map<String, Invoker> getMethods = new HashMap<>();
/* setter方法中参数值类型的Map,key为属性名称,value为对应的参数类型 */
private final Map<String, Class<?>> setTypes = new HashMap<>();
/* getter方法中返回值类型的Map,key为属性名称,value为对应的返回值类型 */
private final Map<String, Class<?>> getTypes = new HashMap<>();
/* 默认构造器 */
private Constructor<?> defaultConstructor;
/* 所有属性名称的集合,key为属性名称大写,value为对应的属性名称 */
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
}
- 了解完基础类信息,来看 forClass() 方法就简单许多
/* 传入 type 类型与 反射工厂,返回一个 MetaClass 的实例 */
public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
return new MetaClass(type, reflectorFactory);
}
/* MetaClass的构造方法,findForClass() 回看reflectorFactory的实现类,一般为DefaultReflectorFactory */
private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
this.reflectorFactory = reflectorFactory;
this.reflector = reflectorFactory.findForClass(type);
}
2.2 metaConfig.hasSetter()
- 是否有属性对应的 setter 方法
public boolean hasSetter(String name) {
PropertyTokenizer prop = new PropertyTokenizer(name);
if (prop.hasNext()) {
if (reflector.hasSetter(prop.getName())) {
MetaClass metaProp = metaClassForProperty(prop.getName());
return metaProp.hasSetter(prop.getChildren());
} else {
return false;
}
} else {
return reflector.hasSetter(prop.getName());
}
}
- 来看 PropertyTokenizer 类(只看属性猜类的作用)
/* 实现 Iterator,即为一个迭代器
* name: 属性名称
* indexedName:当前遍历属性名称
* index: 当前下标?(还没用到,等回头确认)
* children: 孩子节点名称?(还没用到,等回头确认)
* */
public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
private String name;
private final String indexedName;
private String index;
private final String children;
}
- reflector.hasSetter(prop.getName()):属性名称是否有对应的 setter 方法
/* setMethods: 就是一个 HashMap */
public boolean hasSetter(String propertyName) {
return setMethods.keySet().contains(propertyName);
}
2.3 Resources.classForName()
- 通过类名加载类
public static Class<?> classForName(String className) throws ClassNotFoundException {
return classLoaderWrapper.classForName(className);
}
- ClassLoaderWrapper 类
public Class<?> classForName(String name) throws ClassNotFoundException {
return classForName(name, getClassLoaders(null));
}
/* 底层使用 ClassLoader 类加载器,通过 类名 加载类信息,找不到返回 null */
Class<?> classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
for (ClassLoader cl : classLoader) {
if (null != cl) {
try {
Class<?> c = Class.forName(name, true, cl);
if (null != c) {
return c;
}
} catch (ClassNotFoundException e) {
// we'll ignore this until all classloaders fail to locate the class
}
}
}
throw new ClassNotFoundException("Cannot find class: " + name);
}
2.4 resolveClass(String alias)
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 <T> Class<? extends T> resolveAlias(String alias) {
return typeAliasRegistry.resolveAlias(alias);
}
- TypeAliasRegistry 类
/* typeAliases: 就是一个 HashMap */
@SuppressWarnings("unchecked")
public <T> Class<T> resolveAlias(String string) {
try {
if (string == null) {
return null;
}
// issue #748
String key = string.toLowerCase(Locale.ENGLISH);
Class<T> value;
if (typeAliases.containsKey(key)) {
value = (Class<T>) typeAliases.get(key);
} else {
value = (Class<T>) Resources.classForName(string);
}
return value;
} catch (ClassNotFoundException e) {
throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + e, e);
}
}
3. typeAlias
3.1 registerAliases(typeAliasPackage)
- TypeAliasRegistry 类
public void registerAliases(String packageName) {
registerAliases(packageName, Object.class);
}
/* ResolverUtil: 处理工具类
* 1. 生成一个 ResolverUtil 实例
* 2. new ResolverUtil.IsA(superType): 生成一个 Test 实例,
* find():将 packageName 包下与Test 匹配的 .class文件添加进 matches
* 3. 获取 matches 为 typeSet,循环 class 类,若不为 匿名类&&接口&&成员类,添加进 typeAliases
* */
public void registerAliases(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();
for (Class<?> type : typeSet) {
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
registerAlias(type);
}
}
}
- ResolverUtil 类(部分属性和方法)
public class ResolverUtil<T> {
private static final Log log = LogFactory.getLog(ResolverUtil.class);
private Set<Class<? extends T>> matches = new HashSet<>();
public interface Test {
boolean matches(Class<?> type);
}
public static class IsA implements Test {
private Class<?> parent;
public IsA(Class<?> parentType) {
this.parent = parentType;
}
/* 是否是相同的类或接口的 类对象表示,或是父类或超类或接口 */
@Override
public boolean matches(Class<?> type) {
return type != null && parent.isAssignableFrom(type);
}
@Override
public String toString() {
return "is assignable to " + parent.getSimpleName();
}
}
public ResolverUtil<T> find(Test test, String packageName) {
String path = getPackagePath(packageName);
try {
List<String> children = VFS.getInstance().list(path);
for (String child : children) {
if (child.endsWith(".class")) {
addIfMatching(test, child);
}
}
} catch (IOException ioe) {
log.error("Could not read package: " + packageName, ioe);
}
return this;
}
/* 包名 "." 换成 "/" */
protected String getPackagePath(String packageName) {
return packageName == null ? null : packageName.replace('.', '/');
}
/* 若类型匹配,将type 存储进 matches */
@SuppressWarnings("unchecked")
protected void addIfMatching(Test test, String fqn) {
try {
String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
ClassLoader loader = getClassLoader();
if (log.isDebugEnabled()) {
log.debug("Checking to see if class " + externalName + " matches criteria [" + test + "]");
}
Class<?> type = loader.loadClass(externalName);
if (test.matches(type)) {
matches.add((Class<T>) type);
}
} catch (Throwable t) {
log.warn("Could not examine class '" + fqn + "'" + " due to a " +
t.getClass().getName() + " with message: " + t.getMessage());
}
}
public Set<Class<? extends T>> getClasses() {
return matches;
}
}
3.2 registerAlias(Class<?> type)
- 为 type 注册别名
- TypeAliasRegistry 类
/* 若注册有设置别名,获取注册配置的别名 */
public void registerAlias(Class<?> type) {
String alias = type.getSimpleName();
Alias aliasAnnotation = type.getAnnotation(Alias.class);
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
registerAlias(alias, type);
}
/* 1.将别名转换为小写(即别名不区分大小写),
* 2. 判断别名是否被注册(依据为存在别名key且Value不为传入的value)
* 3. 添加别名进 typeAliases
* */
public void registerAlias(String alias, Class<?> value) {
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
}
// issue #748
String key = alias.toLowerCase(Locale.ENGLISH);
if (typeAliases.containsKey(key) && typeAliases.get(key) != null && !typeAliases.get(key).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + typeAliases.get(key).getName() + "'.");
}
typeAliases.put(key, value);
}
4. plugin、objectFactory、objectWrapperFactory、reflectorFactoryElement
- 这部分的函数在前面有体现过,newInstance():使用空构造函数创建一个实例
5. environments
5.1 isSpecifiedEnvironment(String id)
- 判断当前 id 的值与指定的 environment 是否相同
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;
}
5.2 transactionManagerElement(XNode context)
- 类似解析其他的节点,这里为解析 transactionManager 节点
/* 获取 type 指定的类型、property属性,处理type类型并创建实例 factory,设置属性值后返回 */
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.");
}
5.3 dataSourceElement(XNode context)
- 类似解析其他的节点,这里为解析 dataSource 节点
/* 获取 type 指定的类型、property属性,处理type类型并创建实例 factory,设置属性值后返回 */
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.");
}
6. databaseIdProvider
- 用到的方法在前面都有提及,不再赘述。。
7. typeHandler
7.1 register(String packageName)
- TypeHandlerRegistry 类
/* 与 Aliases 的注册类似,但这里的 matches 判断类为 TypeHandler.class */
public void register(String packageName) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
for (Class<?> type : handlerSet) {
/* 非匿名类 && 非接口 && 非抽象类(Modifier: 修饰符) */
if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
register(type); // 7.3.1 的重载方法
}
}
}
7.2 resolveJdbcType(String alias)
- 通过名称获取 JdbcType
/* JdbcType: 枚举类 */
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);
}
}
7.3 register()
- 有 n 多个重载函数
7.3.1 register(Class<?> typeHandlerClass)
- 若注解@MappedTypes 存在 value 值,调用 7.3.2 的重载函数
- 若注解@MappedTypes 不存在 value 值,先生成 typeHandlerClass 的实例,再调用 XXX 的重载函数
public void register(Class<?> typeHandlerClass) {
boolean mappedTypeFound = false;
MappedTypes mappedTypes = typeHandlerClass.getAnnotation(MappedTypes.class);
if (mappedTypes != null) {
for (Class<?> javaTypeClass : mappedTypes.value()) {
register(javaTypeClass, typeHandlerClass);
mappedTypeFound = true;
}
}
if (!mappedTypeFound) {
register(getInstance(null, typeHandlerClass));
}
}
7.3.2 register(Class<?> javaTypeClass, Class<?> typeHandlerClass)
- 先生成 typeHandlerClass 的实例,再继续调用 7.3.3 的重载函数
public void register(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
register(javaTypeClass, getInstance(javaTypeClass, typeHandlerClass));
}
7.3.3 register(Class javaType, TypeHandler<? extends T> typeHandler)
- 这里就做了一个 javaType 的强制转型,再继续调用 7.3.4 的重载函数
public <T> void register(Class<T> javaType, TypeHandler<? extends T> typeHandler) {
register((Type) javaType, typeHandler);
}
7.3.4 register(Type javaType, TypeHandler<? extends T> typeHandler)
- 若注解@MappedJdbcTypes 存在 value 值,调用 7.3.5 的重载函数,handledJdbcType 不为 null
- 若注解@MappedJdbcTypes 不存在 value 值 或者 注解@MappedJdbcTypes 的value 值为 null,,调用 7.3.5 的重载函数,handledJdbcType 为 null
private <T> void register(Type javaType, TypeHandler<? extends T> typeHandler) {
MappedJdbcTypes mappedJdbcTypes = typeHandler.getClass().getAnnotation(MappedJdbcTypes.class);
if (mappedJdbcTypes != null) {
for (JdbcType handledJdbcType : mappedJdbcTypes.value()) {
register(javaType, handledJdbcType, typeHandler);
}
if (mappedJdbcTypes.includeNullJdbcType()) {
register(javaType, null, typeHandler);
}
} else {
register(javaType, null, typeHandler);
}
}
7.3.5 register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler)
- 首先来看 TypeHandlerRegistry 类的部分属性
public final class TypeHandlerRegistry {
private final Map<JdbcType, TypeHandler<?>> jdbcTypeHandlerMap = new EnumMap<>(JdbcType.class);
private final Map<Type, Map<JdbcType, TypeHandler<?>>> typeHandlerMap = new ConcurrentHashMap<>();
private final TypeHandler<Object> unknownTypeHandler = new UnknownTypeHandler(this);
private final Map<Class<?>, TypeHandler<?>> allTypeHandlersMap = new HashMap<>();
private static final Map<JdbcType, TypeHandler<?>> NULL_TYPE_HANDLER_MAP = Collections.emptyMap();
}
- 终点重载方法:将javaType、jdbcType、handler 存进 typeHandlerMap、allTypeHandlersMap
private void register(Type javaType, JdbcType jdbcType, TypeHandler<?> handler) {
if (javaType != null) {
Map<JdbcType, TypeHandler<?>> map = typeHandlerMap.get(javaType);
if (map == null || map == NULL_TYPE_HANDLER_MAP) {
map = new HashMap<>();
typeHandlerMap.put(javaType, map);
}
map.put(jdbcType, handler);
}
allTypeHandlersMap.put(handler.getClass(), handler);
}
7.3.6 register(Class<?> javaTypeClass, JdbcType jdbcType, Class<?> typeHandlerClass)
- 先生成 typeHandlerClass 的实例,再继续调用 7.3.7 的重载函数
public void register(Class<?> javaTypeClass, JdbcType jdbcType, Class<?> typeHandlerClass) {
register(javaTypeClass, jdbcType, getInstance(javaTypeClass, typeHandlerClass));
}
7.3.7 register(Class type, JdbcType jdbcType, TypeHandler<? extends T> handler)
- 先进行 type 的强制转型,再继续调用 7.3.5 的重载函数
public <T> void register(Class<T> type, JdbcType jdbcType, TypeHandler<? extends T> handler) {
register((Type) type, jdbcType, handler);
}
7.4 getInstance()
- 传入 类型处理器TypeHandler 与类型 javaType,生成一个管理 javaType 的处理器
/* 判断 javaType 是否为 null,判断使用 TypeHandler 的 无参/有参 构造器 */
@SuppressWarnings("unchecked")
public <T> TypeHandler<T> getInstance(Class<?> javaTypeClass, Class<?> typeHandlerClass) {
if (javaTypeClass != null) {
try {
Constructor<?> c = typeHandlerClass.getConstructor(Class.class);
return (TypeHandler<T>) c.newInstance(javaTypeClass);
} catch (NoSuchMethodException ignored) {
// ignored
} catch (Exception e) {
throw new TypeException("Failed invoking constructor for handler " + typeHandlerClass, e);
}
}
try {
Constructor<?> c = typeHandlerClass.getConstructor();
return (TypeHandler<T>) c.newInstance();
} catch (Exception e) {
throw new TypeException("Unable to find a usable constructor for " + typeHandlerClass, e);
}
}
8. mapper
8.1 addMappers(String packageName)
- Configruation 类
public void addMappers(String packageName) {
mapperRegistry.addMappers(packageName);
}
- MapperRegistry
public void addMappers(String packageName) {
addMappers(packageName, Object.class);
}
/* 将与 Object.class类 matches 匹配的 */
public void addMappers(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
for (Class<?> mapperClass : mapperSet) {
addMapper(mapperClass);
}
}
- 真正工作的 addMapper 方法
/* 若 type 为非接口,不做任何操作,也不报错
* MapperProxyFactory: mapper 代理工厂,为创建 mapper 实例用
* MapperAnnotationBuilder: 通过 type 的名称(UserMapper)加载 (UserMapper.)xml 文件, 并进行parse()解析
* */
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.put(type, new MapperProxyFactory<>(type));
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
8.2 resource、url
- 可以看到,resource、url 通过加载指定的 xml 文件,构造 XMLMapperBuilder 类,进行 parse() 解析,这不就类似 mybatis-config.xml。篇幅原因,新开一片讲解 Mapper.xml 的详细解析。
8.3 class
- 通过 classForName(“classname”) 架子啊 class 指定的类型,直接调用添加 type 类型的方法,然后通过 type 名称查找 xml 文件并解析。
public <T> void addMapper(Class<T> type) {
mapperRegistry.addMapper(type);
}