【Mybatis】【基础设施】【四】Mybatis源码解析-ResolverUtil解析工具
1 前言
上一节我们在解析别名的时候,会有个package的标签,会获取包名下的所有类的信息,就是用到了ResolverUtil这个工具去获取的,那么我们本节看下这个工具的真实面目。
2 源码分析
那么我们先来整体看下类的结构信息:
2.1 内部接口及其实现
可以看到内部一个Test接口,和两个具体实现类,那么我们来看下:
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) { // 其实就是调用类的isAssignableFrom 来判断是不是父子关系 return type != null && parent.isAssignableFrom(type); } @Override public String toString() { return "is assignable to " + parent.getSimpleName(); } }
public static class AnnotatedWith implements Test { private Class<? extends Annotation> annotation; public AnnotatedWith(Class<? extends Annotation> annotation) { this.annotation = annotation; } @Override public boolean matches(Class<?> type) {
// 调用isAnnotationPresent 也就是判断存在注解么 return type != null && type.isAnnotationPresent(annotation); } @Override public String toString() { return "annotated with @" + annotation.getSimpleName(); } }
内部接口以及两个实现都比较简单哈,我们继续看几个重要的方法。
2.2 find查找
public ResolverUtil<T> find(Test test, String packageName) { // 包名转路径 其实就是.转换成/ String path = getPackagePath(packageName); try { // VFS我们上节说了 就是加载路径下的文件名出来 List<String> children = VFS.getInstance().list(path); for (String child : children) { // 如果是.class结尾的,根据test进行具体匹配判断 if (child.endsWith(".class")) { addIfMatching(test, child); } } } catch (IOException ioe) { log.error("Could not read package: " + packageName, ioe); } return this; }
2.3 findAnnotated注解型查找
public ResolverUtil<T> findAnnotated(Class<? extends Annotation> annotation, String... packageNames) { if (packageNames == null) { return this; } // 创建注解的匹配器 Test test = new AnnotatedWith(annotation); for (String pkg : packageNames) { // 调用find进行匹配查找 find(test, pkg); } return this; }
2.4 findImplementations类型查找
public ResolverUtil<T> findImplementations(Class<?> parent, String... packageNames) { if (packageNames == null) { return this; } // 创建类型匹配器 Test test = new IsA(parent); for (String pkg : packageNames) { // 调用find 匹配查找 find(test, pkg); } return this; }
2.5 addIfMatching加载类
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()); } }
3 示例
4 小结
好了,关于ResolverUtil工具的使用就介绍到这里,有理解不对的地方欢迎指正哈。