mybatis-3.4.0---资源获取系列-ClassLoader操作

时间:2021-01-06 19:40:22

    其实mybatis框架,或者是说spring框架,都是从读取配置文件开始的,之后是各种操作,这种编程方式的有点就是,我们下载别人的jar包框架之后,修改一下配置文件就可以使用了,

这也是编码从硬编码到配置编码的过程演变,我们平常写代码的时候,也要注意从硬编码改成配置编码,其实有的时候配置编码都是被逼迫的,因为,老大总是要修改,没有办法,不可能每次都在自己机器上改好,然后上传服务器,没有那个闲工夫,如果使用配置文件,修改一下配置文件,保存就行了,就是这么的任性。

    我们先从mybatis的获取资源的过程来说:首先,先不管mybatis怎么处理这个配置文件,但是第一步(虽然是面向对象编程,我一度被面向对象给迷惑了,以为面向对象就不是面向过程了,但是后来证明其实任何程序都是面向过程的,面向对象其实就是一种分析方法和分析思维而已,真是名字吓死人):读取资源无外乎就是获取流,只要我们能拿到流,我们就想操作就怎么操作,但是如何才能获取流,这是个问题,我们使用File的时候,总是出现,FileNotFoundException异常,这个异常就是找不到文件,有的时候文件明明就在那儿,但是还是获取不到,就是这么个郁闷的心情啊。mybatis就是使用ClassLoader获取资源的,为什么使用ClassLoader获取流,因为java有一个jvm:就是java的虚拟机,既然是虚拟机,就是安装在windows或者是linux上一个操作系统,jvm有自己寻找资源的方式,并且ClassLoader就是类加载器,他既然能加载class,class也是使用流的方式加载的,那么,就能加载我们的文件资源,道理都是一样子的。我们讲完了,看看mybatis的源码操作

org.apache.ibatis.io.
ClassLoaderWrapper
这个是mybatis包装的一个获取ClassLoader的包装类,其中只有三个方法值得我们去看,其他的都是重载:

第一个是:获取五种类类加载器(ClassLoader)的方法


/**
* 获取多个ClassLoader,这一步是必须的,因为,我们就是从这个加载器中获取资源的流的
*五种类加载器:自己传入的、默认的类加载器、当前线程的类加载器、本类的类加载器、系统类加载器
* @param classLoader 我们定义的自己的类加载器
* @return 类加载器的数组
*/
ClassLoader[] getClassLoaders(ClassLoader classLoader) {
return new ClassLoader[]{
classLoader,
defaultClassLoader,
Thread.currentThread().getContextClassLoader(),
getClass().getClassLoader(),
systemClassLoader};
}



第二个方法是:记载资源为InputStream的形式输出
/**
* 从一个ClassLoader中获取资源的流,这就是我们的目的
*
* @param resource 资源的地址
* @param classLoader 类加载器
* @return
*/
InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
for (ClassLoader cl : classLoader) {
if (null != cl) {

// try to find the resource as passed
InputStream returnValue = cl.getResourceAsStream(resource);

// now, some class loaders want this leading "/", so we'll add it and try again if we didn't find the resource
if (null == returnValue) {
returnValue = cl.getResourceAsStream("/" + resource);
}

if (null != returnValue) {
return returnValue;
}
}
}
return null;
}

第三个是:获取资源,以URL的形式输出:(URL可以通过openConnection、getInputStream的形式获取流,不知道为什么提供这个方法)
/* * Get a resource as a URL using the current class path * * @param resource    - the resource to locate * @param classLoader - the class loaders to examine * @return the resource or null */URL getResourceAsURL(String resource, ClassLoader[] classLoader) {    URL url;    for (ClassLoader cl : classLoader) {        if (null != cl) {            // look for the resource as passed in...            url = cl.getResource(resource);            // ...but some class loaders want this leading "/", so we'll add it            // and try again if we didn't find the resource            if (null == url) {                url = cl.getResource("/" + resource);            }            // "It's always in the last place I look for it!"            // ... because only an idiot would keep looking for it after finding it, so stop looking already.            if (null != url) {                return url;            }        }    }    // didn't find it anywhere.    return null;}

第四个也要看看:是通过当前的类加载器加载我们的类:
/* * 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) {        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);}