【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工具的使用就介绍到这里,有理解不对的地方欢迎指正哈。

posted @ 2023-02-26 12:28  酷酷-  阅读(48)  评论(0编辑  收藏  举报