Mybatis源码-ClassLoaderWrapper(类加载器包装类)

该类属于mybatis的io包的,主要用来加载类,加载器是有多种,一个类应该用哪个类加载器呢,这个类就是做这个层封装,将多个类加载器进行排序。

1、源码

/**
 * A class to wrap access to multiple class loaders making them work as one
 * 将多个类型加载器放入当前类加载器中使用
 * 1.自定义类加载器 > 默认类加载器  > 当前线程Id上下文类加载器 > 当前类的加载器 > 系统类加载器
 * 2.封装加载类资源有三种,一种返回URL、一种是返回InputStream,最后一种根据类名返回Class
 * 3. 在实例化该对象的时候默认会赋值系统类加载器
 *
 * @author Clinton Begin
 */
public class ClassLoaderWrapper {

  /**
   * 默认类加载器
   */
  ClassLoader defaultClassLoader;

  /**
   * 系统类加载器
   */
  ClassLoader systemClassLoader;

  /**
   * 在实例化该ClassLoaderWrapper 自动获取系统类加载器
   */
  ClassLoaderWrapper() {
    try {
      systemClassLoader = ClassLoader.getSystemClassLoader();
    } catch (SecurityException ignored) {
      // AccessControlException on Google App Engine
    }
  }

  /**
   * Get a resource as a URL using the current class path
   * 获取当前类路径的资源作为URL返回
   * @param resource - the resource to locate
   * @return the resource or null
   */
  public URL getResourceAsURL(String resource) {
    return getResourceAsURL(resource, getClassLoaders(null));
  }

  /**
   * Get a resource from the classpath, starting with a specific class loader
   * 获取当前类路径的资源作为URL返回,指定类加载器
   * @param resource    - the resource to find
   * @param classLoader - the first classloader to try
   * @return the stream or null
   */
  public URL getResourceAsURL(String resource, ClassLoader classLoader) {
    return getResourceAsURL(resource, getClassLoaders(classLoader));
  }

  /**
   * Get a resource from the classpath
   * 从当前类路径下获取资源以InputStream返回
   * @param resource - the resource to find
   * @return the stream or null
   */
  public InputStream getResourceAsStream(String resource) {
    return getResourceAsStream(resource, getClassLoaders(null));
  }

  /**
   * Get a resource from the classpath, starting with a specific class loader
   * 从当前类路径下获取资源以InputStream返回, 指定类加载器
   * @param resource    - the resource to find
   * @param classLoader - the first class loader to try
   * @return the stream or null
   */
  public InputStream getResourceAsStream(String resource, ClassLoader classLoader) {
    return getResourceAsStream(resource, getClassLoaders(classLoader));
  }

  /**
   * Find a class on the classpath (or die trying)
   * 在当前类路径下找某个类
   * @param name - the class to look for
   * @return - the class
   * @throws ClassNotFoundException Duh.
   */
  public Class<?> classForName(String name) throws ClassNotFoundException {
    return classForName(name, getClassLoaders(null));
  }

  /**
   * Find a class on the classpath, starting with a specific classloader (or die trying)
   * 在当前类路径下找某个类, 指定类加载器
   * @param name        - the class to look for
   * @param classLoader - the first classloader to try
   * @return - the class
   * @throws ClassNotFoundException Duh.
   */
  public Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
    return classForName(name, getClassLoaders(classLoader));
  }

  /**
   * Try to get a resource from a group of classloaders
   * 拿一个类加载对象去加载资源
   * @param resource    - the resource to get
   * @param classLoader - the classloaders to examine
   * @return the resource or null
   */
  InputStream getResourceAsStream(String resource, ClassLoader[] classLoader) {
    for (ClassLoader cl : classLoader) {
      //循环遍历类加载
      if (null != cl) {
        // 如果类加载器不为空,用jdk自带类加载器去加载对应资源
        // 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;
  }

  /**
   * Get a resource as a URL using the current class path
   * 这个其实跟上getResourceAsStream类似,这里返回时URL,url.openStream()就是InputStream
   * @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
   * 根据类名获取对应Class
   * @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);

  }

  /**
   * 这个方法就是该类的核心,类加载器的顺序
   * 自定义类加载器 > 默认类加载器  > 当前线程Id上下文类加载器 > 当前类的加载器 > 系统类加载器
   * @param classLoader
   * @return
   */
  ClassLoader[] getClassLoaders(ClassLoader classLoader) {
    return new ClassLoader[]{
        classLoader,
        defaultClassLoader,
        Thread.currentThread().getContextClassLoader(),
        getClass().getClassLoader(),
        systemClassLoader};
  }

}

2、总结

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

你可能感兴趣的:(mybatis源码,MyBatis源码)