2.4、mybatis源码分析--基础模块之资源加载

  • 关于资源加载,重要的一点是要理解java的类加载原理。因此本篇博客首先介绍java的类加载机制,然后在理解mybatis中是怎么加载资源的。

一、java类加载器

  • java中的类加载器负载加载来自文件系统、网络或者其他来源的类文件。jvm的类加载器默认使用的是双亲委派模式。

1、类加载器种类

java中的类加载器负载加载来自文件系统、网络或者其他来源的类文件。jvm的类加载器默认使用的是双亲委派模式。三种默认的类加载器Bootstrap ClassLoader、Extension ClassLoader和System ClassLoader(Application ClassLoader)每一个中类加载器都确定了从哪一些位置加载文件。

  • Bootstrap ClassLoader:负责加载JDK自带的rt.jar包中的类文件,是所有类加载的父类
  • Extension ClassLoader:负责加载java的扩展类库从jre/lib/ect目录或者java.ext.dirs系统属性指定的目录下加载类,是System ClassLoader的父类加载器
  • System ClassLoader:负责从classpath环境变量中加载类文件


    类加载器结构图jpg.jpg

2、双亲委派模式

原理

根据双亲委派模式,在加载类文件的时候,子类加载器首先将加载请求委托给它的父加载器,父加载器会检测自己是否已经加载过类,如果已经加载则加载过程结束,如果没有加载的话则请求继续向上传递直Bootstrap ClassLoader。如果请求向上委托过程中,如果始终没有检测到该类已经加载,则Bootstrap ClassLoader开始尝试从其对应路劲中加载该类文件,如果失败则由子类加载器继续尝试加载,直至发起加载请求的子加载器为止。

两个保证

1、子类加载器可以使用父类加载器已经加载的类,而父类加载器无法使用子类加载器已经加载的
2、类父类加载器已经加载过的类无法被子类加载器再次加载

3、自定义类加载器

  • 通过实现ClassLoader类方式实现自定义类加载器,以满足特定的需求
  • 举例说明比如tomcat中的类加载器,结构图:


    tomcat中类加载器结构图.jpg

首先tomcat提供了一个Common ClassLoader,负责加载Tomcat使用的类和jar包以及应用通用的一些类和jar包,而它的父加载器是System ClassLoader。同时tomcat会为每一个部署应用创建一个唯一的类加载器,也就是WebApp ClassLoader,负责加载该应用的WEB-INF/lib目录下面的以及WEB-INF/classes目录下的class文件。实现了web应用的隔离。WebApp ClassLoader父加载器是Common ClassLoader,所以不同的web应用可以使用Common ClassLoader加载的共享类库。

4、双亲委派模式的优缺点及SPI的产生

待定...

二、mybatis中的类ClassLoaderWrapper

  • ClassLoaderWrapper是ClassLoader的包装器,其中包含许多的ClassLoader对象,通过调用多个类加载器的使用顺序,ClassLoaderWrapper可以确保返回给系统使用的是正确的类加载器。
    属性及构造器
public class ClassLoaderWrapper {
    //应艳红指定的默认类加载器
  ClassLoader defaultClassLoader;
  //System ClassLoader
  ClassLoader systemClassLoader;

  ClassLoaderWrapper() {
    try {
      systemClassLoader = ClassLoader.getSystemClassLoader();
    } catch (SecurityException ignored) {
      // AccessControlException on Google App Engine   
    }
  }

功能方法

1.在classpath中找到类
    public Class<?> classForName(String name) throws ClassNotFoundException {
    return classForName(name, getClassLoaders(null));
  }
 2.从classpath中找到resource
   public InputStream getResourceAsStream(String resource) {
    return getResourceAsStream(resource, getClassLoaders(null));
  }
3.Get a resource as a URL using the current class path,为例子说明
   public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
    return getResourceAsStream(resource, getClassLoaders(classLoader));
  }
  //获取类加载器数组
    ClassLoader[] getClassLoaders(ClassLoader classLoader) {
    return new ClassLoader[]{
        classLoader,//传入的类加载
        defaultClassLoader,//默认的类加载
        Thread.currentThread().getContextClassLoader(),//当前线程加载器
        getClass().getClassLoader(),//当前类加载器
        systemClassLoader};//系统类加载器
  }

 URL getResourceAsURL(String resource, ClassLoader[] classLoader) {
    URL url;
    //遍历数组
    for (ClassLoader cl : classLoader) {
      if (null != cl) {
      //调用ClassLoader.getResource方法查找指定的资源
        url = cl.getResource(resource);
        if (null == url) {
        //尝试以/开头再次查找
          url = cl.getResource("/" + resource);
        }
        if (null != url) {
          return url;
        }
      }
    }
    return null;
  }

三、Resources

  • Resource是一个提供了许多静态方法的工具类其中就封装了一个ClassLoaderWrapper对象用于加载资源文件,加载资源最终调用者是ClassLoaderWrapper
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容