Mybatis IO模块分析

·  阅读 255

模块总览

IO模块总览
包括了这几个类:

  • ClassLoaderWrapper:ClassLoader的包装类。
  • DefaultVFS:VFS的默认实现类。
  • ExternalResources:已经废弃了。
  • JBoss6VFS:JBoss 6实现的VFS。
  • ResolverUtil:用来通过某种方式来查找类,如果满足某个条件就查出该类。
  • Resources:通过类加载器简单的访问资源。
  • VFS:是提供用于访问应用内资源的一个简便接口。

ClassLoaderWrapper

作用

使用5种类加载器,one by one查找资源,只要其中一个命中,就OK

  1. 自定义类加载器 > 默认类加载器 > 当前线程Id上下文类加载器 > 当前类的加载器 > 系统类加载器
  2. 封装加载类资源有三种,一种返回URL、一种是返回InputStream,最后一种根据类名返回Class
  3. 在实例化该对象的时候默认会赋值系统类加载器

类图

ClassLoaderWrapper类

Thinking

  • 为什么需要用5种不同的类加载器

尽最大可能找到指定的资源

  • 每种类加载器的异同

Resources

作用

简化资源文件的获取。 主要是通过ClassLoaderWrapper(封装ClassLoader读取文件)进行文件加载

  • 对于简单的只读文本数据,加载为 Reader
  • 对于简单的只读二进制或文本数据,加载为 InputStream
  • 对于可读写的二进制或文本文件,加载为 File
  • 对于只读的配置属性文件,加载为 Properties
  • 对于只读的通用资源,加载为 URL

类图

Resources类图

Thinking

  • 有了ClassLoaderWrapper,为啥又定义Resources

ClassLoderWrapper作为Resouces类的一个成员变量,将前者提供的方法都包装成静态方法,方便调用。 并且扩展了其他资源读取的方法,eg: getResourceAsProperties()。看着有点像是装饰模式的样子~~

ResolverUtil

作用

ResolverUtil用于查找在类路径可用并满足任意条件的类。最常见的两种情况是一个类继承或实现了另一个类, 或者此类被指定的注解标记了。并且,通过使用Test类,可以满足任意条件的搜索。即找一个package下满足条件的所有类

类图

ResolverUtil类图

主要方法

  /**
   * 主要的方法,找一个package下满足条件的所有类,被TypeHandlerRegistry, MapperRegistry, TypeAliasRegistry调用
   * 1. 浏览提供的包及其子包的类
   * 2. 每个发现的类都会被提供给Test类,如果Test类的方法返回true就保留
   * 3. 累的类可以通过getClasses()方法获得
   */
  public ResolverUtil<T> find(Test test, String packageName) {
    String path = getPackagePath(packageName);

    try {
      // 通过VFS来深入jar包里面去找一个class
      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;
  }
复制代码

UT

在当前包中查找所有被CacheNamespace注解修饰的类

  @Test
  void findAnnotated() {
    ResolverUtil<Object> resolverUtil = new ResolverUtil<>();
    // 在当前包中查找所有被CacheNamespace注解修饰的类 
    resolverUtil.findAnnotated(CacheNamespace.class, this.getClass().getPackage().getName());
    Set<Class<?>> classSets = resolverUtil.getClasses();
    //org.apache.ibatis.io.ResolverUtilTest.TestMapper
    assertEquals(classSets.size(), 1);
    classSets.forEach(c -> assertNotNull(c.getAnnotation(CacheNamespace.class)));
  }
复制代码

Thinking

很巧妙的应用了设计模式原则的开发-封闭原则。在这个工具类中,定义了一个内部接口Test和两个Test的内部实现类。 使得我们可以只实现Test接口,而不用修改ResolverUtil的内部方法,即可直接使用ResolverUtilfind方法

public class CustomTest implements Test {
    @Override
    public boolean matches(Class<?> type) {
        if (type == CustomTest.class) {
            return true;
        }
        return false;
    }
}
复制代码

扩展阅读

分类:
后端
标签:
分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改