- 关于资源加载,重要的一点是要理解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

