Mybatis大揭秘.IO

Mybatis大揭秘.IO

Perface

IO模块是mybatis的各种资源加载方式的实现,比如从读取配置文件、如何加载一个class对象等等。

下面是包中的主要成员,出来给大家打个招呼啦

├── ClassLoaderWrapper.java 一个类加载容器包装,为的是方便实现统一的类加载逻辑.

├── DefaultVFS.java 缺省的VFS资源加载实现,关于VFS文章后有链接阅读.

├── ExternalResources.java 扩展资源加载工具类(已废弃)

├── JBoss6VFS.java Jboss6VFS资源加载实现

├── ResolverUtil.java 用于检测类是不是可用的工具类

├── Resources.java Mybatis内部主要使用的资源加载工具类

├── VFS.java VFS资源加载接口定义

可以说这个包主要的作用就是为mybatis框架提供外部资源的读取加载的能力,所以我们挑重点只分析一下两个类:

  • ClassLoaderWrapper.java
  • Resources.java

ClassLoaderWrapper

首先看到作者Clinton的注释是这么写的:

A class to wrap access to multiple class loaders making them work as one.

用来封装对多个类加载器的访问,对外提供统一的行为。

这就是装饰器。

这个类提供了一下几个方法

  • ClassLoaderWrapper 构造方法
  • getClassLoaders private 提供一组类加载器
  • classForName 通过类名加载Class,重载
  • getResourceAsStream 以流的形式加载资源,重载
  • getResourceAsURL 以URL的方式加载资源,重载

ClassLoaderWrapper

ClassLoaderWrapper() {
    try {
        // 一般情况下这个地方应该得到的是AppClassLoader
        systemClassLoader = ClassLoader.getSystemClassLoader();
    } catch (SecurityException ignored) {
        // AccessControlException on Google App Engine
    }
}

构造方法是protected的也就这能在IO包中使用,开闭原则。

从构造方法看到只是初始化了一个类成员变量systemClassLoader,这里默认情况下你会得到的是AppClassLoader对象,也就是我们经常使用的系统类加载器(它负责加载应用classpath目录下的所有jar和class文件),为什么初始化系统类加载器留着疑问到后边解答。

关于更多的类加载器介绍请看链接:Java类加载器

getClassLoaders

ClassLoader[] getClassLoaders(ClassLoader classLoader) {
    return new ClassLoader[]{
            classLoader, //1. the custom CL
            defaultClassLoader, // 2. default CL which provides by use also.
            Thread.currentThread().getContextClassLoader(), // 3. the current thread's CL
            getClass().getClassLoader(), // 4. the current ClassLoaderWrapper's CL
            systemClassLoader}; // 5. try to use the system CL
}

提供了5中类加载器,分别是:

  1. 用户传过来的
  2. 缺省的,其实就是mybatis自己设置的,可能没有值,因为这个field本身没有初始化,唯一的write接口在Resources类中
  3. 当前线程的类加载器
  4. 加载ClassLoaderWrapper的类加载器
  5. 系统类加载器

可以看出来,框架本身希望通过提供这么5中类加载器来完成系统的资源加载,而不是单一的希望通过特定某一个来加载资源。

classForName

public Class classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
        // 先获得一组 CL
        return classForName(name, getClassLoaders(classLoader));
}
/*
 * Attempt to load a class from a group of classloaders
 * @param name        - the class to load
 * @param classLoader - the group of classloaders to examine
 * @return the class
 * @throws ClassNotFoundException - Remember the wisdom of Judge Smails: Well, the world needs ditch diggers, too.
 */
Class classForName(String name, ClassLoader[] classLoader) throws ClassNotFoundException {
    for (ClassLoader cl : classLoader) {// 循环使用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);
}

这个方法其实非常容易理解,就是使用内部提供的多个CL(ClassLoader)逐个尝试加载类,其实就是为了方便使用自己的类加载来加载资源。实现自己的类加载器主要有两个用处:1. 加密,2. 特殊逻辑处理,比如IOC,特殊路径搜索,系统安全控制等。

可用从上面getClassLoaders和for (ClassLoader cl : classLoader)这里的循环看出,框架会优先使用自己定义的类加载器加载,如果加载不到才交给上一级的类加载器,最后才委托给系统类加载器,也就是JVM或者容器的类加载器。

其实这也摆脱了JVM默认提供的双亲委派的逻辑。

getResourceAsStream && getResourceAsURL

这两个方法跟上一个方法类似,都是实现资源加载器的顺序控制。另外提供这两个方法也为框架提供了如配置文件加载的实现。

Resources

这里也不展开了,可以简单看下类的api

  • getDefaultClassLoader
  • getResourceAsFile
  • getResourceAsProperties
  • getResourceAsReader
  • getResourceAsStream
  • getResourceURL
  • getUrlAsProperties
  • getUrlAsReader
  • getUrlAsStream
public class Resources {
   private static ClassLoaderWrapper classLoaderWrapper = new ClassLoaderWrapper();
....
   Resources() {
   }
.....

这个类其实就是通过调用ClassLoaderWrapper来实现更加丰富的资源加载接口:file, properties, reader, stream, URL…

Summary

Mybatis使用了自己的一套资源文件加载逻辑,其目的就是为了实现自己的资源加载方式,这也是很多中间件框架喜欢的方式。比如把mybatis配置文件放到某个带有安全控制的统一服务器上,然后其他应用都通过api的方式来加载配置,这个时候就需要自定义一个类加载器,同时将这个类加载器放到getClassLoaders的前面。

你可能感兴趣的:(06-Scala)