2019独角兽企业重金招聘Python工程师标准>>>
一 ClassLoader
ClassLoader 负责加载来自文件系统,网络系统或其他来源的类文件,JAVA虚拟机中的类加载器使用的是双亲委派模式。
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 加载的共享类库。
三 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}; } }