最终整理一下Tomcat 的ClassLoader创建流程如下:
1. 入口
Bootstrap bootstrap = new Bootstrap();
bootstrap.init();
initClassLoaders();
ClassLoader commonLoader = createClassLoader("common", null);
createClassLoader("common", null) {
String value = CatalinaProperties.getProperty("common.loader");
if (value == null || “”) {
return commonLoader = parent. 即 null.
} else {
将value对应的目录和文件所在目录转成Repository的数组,并执行
ClassLoaderFactory.createClassLoader(repositories, parent);
将repository的jar文件(一般都是jar)转化成URL存入到数组中。执行:
return new URLClassLoader(array);
}
}
如果 commonLoader==null, 则 commonLoader=parent 亦为null,表示无需额外资源加载。
2. new URLClassLoader(array) 函数
URLClassLoader(URL[] urls)
SecureClassLoader()
ClassLoader() {
this(checkCreateClassLoader(), getSystemClassLoader());
}
这里前者就是check RuntimePermission("createClassLoader") 运行时权限
getSystemClassLoader()就是生成系统类 cloassloader. 主要调用 initSystemClassLoader(); 函数
initSystemClassLoader()
sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
Launcher实例化的时候调用下面代码:
new Launcher() {
// 创建扩展类加载器,主要加载System.getProperty("java.ext.dirs")目录下相关资源
// 例如: $JAVA_HOME/lib/ext, $JAVA_HOME/jre/lib/ext
ClassLoader extcl = ExtClassLoader.getExtClassLoader();
// 创建 “java类路径”加载器,主要加载 System.getProperty("java.class.path") 目录下相关资源
// 可以通过 ps –ef | grep java 查看 –classpath 得到。
ClassLoader loader = AppClassLoader.getAppClassLoader(extcl);
}
上述也进一步说明编写自己 classloader 的必要行。
启动类加载器只加载JVM启动所必需的类,为C编写,加载的如 java.*,javax.*等文件。
扩展类加载器只加载 java.ext.dirs 目录下的资源
应用类加载器只加载 java.class.path 里面,即 –classpath 对应的资源。
那么 tomcat/lib 等资源如何加载呢? 这就是 tomcat commonClassLoader 的用途了。
同理 对于具体的webapp,没有目前的加载器没有加载,需要写自己的加载器加载 web/lib, web/classes等资源。
3. ExtClassLoader.getExtClassLoader();
URLStreamHandlerFactory factory = new Factory();
File[] dirs = getExtDirs(); // System.getProperty("java.ext.dirs");
new ExtClassLoader(dirs);
super(getExtURLs(dirs), null, factory); // 将dir中文件转成 java.net.URL[]
即:
URLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
回到了步骤2,但是这次带了parent=null, 和 factory.
步骤而的 super() 变成 super(parent);
这样最终的ClassLoader如下:
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}
这里直接传入 parent classloader, 就不在实例化系统类加载器了。
}
4. ClassLoader 具体工作
ClassLoader有多个构造函数,但最终都是通过下面的构造函数工作。
// 父类加载器,ext的为null.
private final ClassLoader parent;
// 设置父classloader和初始化一些属性。
private ClassLoader(Void unused, ClassLoader parent) {
this.parent = parent;
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
package2certs = new ConcurrentHashMap<>();
domains =
Collections.synchronizedSet(new HashSet<ProtectionDomain>());
assertionLock = new Object();
} else {
// no finer-grained lock; lock on the classloader instance
parallelLockMap = null;
package2certs = new Hashtable<>();
domains = new HashSet<>();
assertionLock = this;
}
}
其实这个类里比较有用的是 loadClss(), findClass(), 以及 defineClass() 等。
通过上述,将 ExtClassLoader 对象(extcl)创建出来了
下面继续AppClassLoader的class loader创建
5. Launcher的构造函数有 ClassLoader loader = AppClassLoader.getAppClassLoader(extcl);
public static ClassLoader getAppClassLoader(final ClassLoader extcl) throws IOException {
// 加载资源的路径为 classpath 路径
final String s = System.getProperty("java.class.path");
final File[] path = (s == null) ? new File[0] :
Java ClassLoader机制分析 -- Tomcat commloader 例说
最新推荐文章于 2021-05-06 22:35:58 发布
本文详细分析了Tomcat中ClassLoader的创建过程,从Bootstrap开始,逐步讲解了如何创建commonLoader,涉及URLClassLoader的构造及其父类加载器的设置。此外,还探讨了ExtClassLoader和AppClassLoader的创建,以及类加载的步骤,包括findLoadedClass、loadClass、findClass和defineClass等关键方法的作用。通过这个过程,我们理解了Tomcat如何加载自定义路径下的资源以及自定义类加载器的重要性。
摘要由CSDN通过智能技术生成