Mybatis 的類加載器(ClassLoaderWrapper)

一 ClassLoader 

  ClassLoader 負責加載來自文件系統,網絡系統或其餘來源的類文件,JAVA虛擬機中的類加載器使用的是雙親委派模式。java

 

   JAVA 虛擬機中的類加載器默認使用的是雙親委派模式,其中有三種默認的類加載器,BootStrapClassLoader,ExtensionClassLoader,SystemClassLoader(AppClassLoader),每種類加載器都已經肯定從哪一個位置加載類文件。apache

二 雙親委派

     根據雙親委派模式,在加載類文件時,子加載器會首先將加載請求委託給它的父加載器,父加載器會檢測本身是否已經加載過該類,若是以加載,則加載過程結束,若是未加載則請求向上傳遞,直到BootStrap ClassLoader。若是始終未檢測到該類被加載,則從BootStrap ClassLoader 開始嘗試從其對應的路勁中加載該類文件,若是加載失敗,則有子類加載器嘗試加載,直至發起請求的子加載器爲止。數組

     雙親委派模式能夠保證兩點tomcat

     一 子加載器能夠使用父加載器已加載的類,但父加載器不能使用子加載器加載的類。安全

    二 父加載器已加載過的類,沒法被子類再次加載,這樣就能夠保證JVM的安全性和穩定性。網絡

  在不少場景中,系統會使用不一樣的類加載器完成不一樣的任務,這裏以tomcat爲例簡單介紹一下。app

  Tomcat 會爲每一個部署的應用建立一個惟一的類加載,也就是WebApp ClassLoader,它負責加載該應用的this

WEB-INF/lib 目錄下的Jar文件以及WEB-INF/classes 目錄下的Class 文件。因爲每一個應用都有本身的WebAppClassLoader。WebAppClassLoader 的父加載器是Common ClassLoader ,因此不一樣的應用能夠使用Common ClassLoader 加載的共享類庫。url

 

三 ClassLoaderWrapper

MyBatis 的IO包中 提供的ClassLoaderWrapper 是一個ClassLoader 的包裝器,其中包含了多個ClassLoader 對象,經過調整多個類加載器的使用順序,ClassLoaderWrapper 能夠確保返回給系統使用的是正確的類加載器。ClassLoaderWrapper 會按照指定的順序依次檢測其中封裝的ClassLoader對象,並從中選取第一個可用的ClassLoader 對象。spa

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

}
相關文章
相關標籤/搜索