Mybatis 的类加载器(ClassLoaderWrapper)

一 ClassLoader 

  ClassLoader 负责加载来自文件系统,网络系统或其他来源的类文件,JAVA虚拟机中的类加载器使用的是双亲委派模式。

102059_SkWd_3218528.png

 

   JAVA 虚拟机中的类加载器默认使用的是双亲委派模式,其中有三种默认的类加载器,BootStrapClassLoader,ExtensionClassLoader,SystemClassLoader(AppClassLoader),每种类加载器都已经确定从哪个位置加载类文件。

二 双亲委派

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

     双亲委派模式可以保证两点

     一 子加载器可以使用父加载器已加载的类,但父加载器不能使用子加载器加载的类。

    二 父加载器已加载过的类,无法被子类再次加载,这样就可以保证JVM的安全性和稳定性。

  在很多场景中,系统会使用不同的类加载器完成不同的任务,这里以tomcat为例简单介绍一下。

  Tomcat 会为每个部署的应用创建一个唯一的类加载,也就是WebApp ClassLoader,它负责加载该应用的

WEB-INF/lib 目录下的Jar文件以及WEB-INF/classes 目录下的Class 文件。由于每个应用都有自己的WebAppClassLoader。WebAppClassLoader 的父加载器是Common ClassLoader ,所以不同的应用可以使用Common ClassLoader 加载的共享类库。

 105922_v2MH_3218528.png

三 ClassLoaderWrapper

MyBatis 的IO包中 提供的ClassLoaderWrapper 是一个ClassLoader 的包装器,其中包含了多个ClassLoader 对象,通过调整多个类加载器的使用顺序,ClassLoaderWrapper 可以确保返回给系统使用的是正确的类加载器。ClassLoaderWrapper 会按照指定的顺序依次检测其中封装的ClassLoader对象,并从中选取第一个可用的ClassLoader 对象。

package org.apache.ibatis.io;

import java.io.InputStream;
import java.net.URL;

/**
 * A class to wrap access to multiple class loaders making them work as one
 *
 * @author Clinton Begin
 */
public class ClassLoaderWrapper {
  // 默认的类加载器
  ClassLoader defaultClassLoader;
  // System ClassLoader
  ClassLoader systemClassLoader;

  ClassLoaderWrapper() {
    try {
     // 初始化SystemClassLoader
      systemClassLoader = ClassLoader.getSystemClassLoader();
    } catch (SecurityException ignored) {
      // AccessControlException on Google App Engine   
    }
  }
  
  
  public URL getResourceAsURL(String resource) {
   //getClassLoaders() 返回ClassLoader[] 数组,指名了类加载器的使用顺序
    return getResourceAsURL(resource, getClassLoaders(null));
  }

 
  public URL getResourceAsURL(String resource, ClassLoader classLoader) {
    return getResourceAsURL(resource, getClassLoaders(classLoader));
  }

  
  public InputStream getResourceAsStream(String resource) {
    return getResourceAsStream(resource, getClassLoaders(null));
  }

 
  public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
    return getResourceAsStream(resource, getClassLoaders(classLoader));
  }

  
  public Class<?> classForName(String name) throws ClassNotFoundException {
    return classForName(name, getClassLoaders(null));
  }

 
  public Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
    return classForName(name, getClassLoaders(classLoader));
  }

  // resource(资源的地址) ,按照ClassLoader[] 加载器的顺序进行加载,返回InputStream
  InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
    for (ClassLoader cl : classLoader) {
      if (null != cl) {

      
        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;
  }

  // 从指定的资源(resource资源的URL)  按顺序(ClassLoader[]中的顺序)加载
  // 加载到就return
  URL getResourceAsURL(String resource, ClassLoader[] classLoader) {

    URL url;
    //遍历ClassLoader 数组
    for (ClassLoader cl : classLoader) {

      if (null != cl) {

        url = cl.getResource(resource);

        if (null == url) {
          url = cl.getResource("/" + resource);
        }

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

      }

    }

    // didn't find it anywhere.
    return null;

  }

  // Class.forName()
  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);

  }

  ClassLoader[] getClassLoaders(ClassLoader classLoader) {
    return new ClassLoader[]{
        //参数指定的类加载器
        classLoader,
        // 系统指定的默认加载器
        defaultClassLoader,
        //当前线程绑定的类加载器
        Thread.currentThread().getContextClassLoader(),
        // 当前类使用的类加载器
        getClass().getClassLoader(),
        // System ClassLoader(App ClassLoader)
        systemClassLoader};
  }

}

 

转载于:https://my.oschina.net/u/3218528/blog/1615394

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值