Tomcat 源代码分析之ClassLoader
此系列文章皆为Tomcat
7.0代码代码分析。
1. ClassLoader基础知识
1.1. Parent-Child委托模型
我们知道Java系统中,类加载器的默认加载方式是采用Parent-Child委托方式加载类的,即就是说,先尝试使用父类加载器加载类,如果没有找到,才自己加载该类,可以看到,这是一个递归的加载过程,核心代码大致如下:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
……
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
…
c = findClass(name);
……
}
}
……
return c;
}
}
很多ClassLoader的继承类都默认了这种加载方式,其中用途比较广泛的有URLClassLoader。
1.2. 类加载器运行时模型:
当一个JVM启动时,至少有三个ClassLoader会被启动:
1. Bootstrap 类加载器
加载Java核心包,它们被置放在(<JAVA_HOME>/lib目录下,这部分是JVM的一部分,往往使用native code完成
2. Extensions类加载器
加载Java扩展包,即位于<JAVA_HOME>/lib/ext下的包,这里要注意的是,有些JVM的这个加载器和Bootstrap类加载器是同一个加载器,而Sun是把二者分开的,其实现类为sun.misc.Launcher$ExtClassLoader。
3. System类加载器
这个类加载器加载CLASSPATH下的类,Sun的 默认实现是sun.misc.Launcher$ExtClassLoader。
这三者之间的父子关系是:Bootstrap类加载器是Extensions类加载器的父类加载器,而Extensions类加载器是System类加载器的父类加载器。
2. Tomcat Classloader模型
Tomcat 7.0的ClassLoader加载层次模型如下图所示:
这个模型和之前Tomcat 5.5之前有些不同,因为之前的除过Common类加载器之外,还有Catalina类加载器和Shared类加载器,这个只能导致更多的配置和概念,已经不再使用了,虽然还可以进行配置。
1. Common类加载器:加载$CATALINA_HOME/lib和$CATALINA_BASE/lib下的class文件和jar包以及旗下的资源文件,这些文件将会被所有Web应用共有,也会被Tomcat运行时用到。其配置在catalina.properties下,如果没有配置,则默认使用System类加载器,配置示例:
common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar
2. App类加载器:Web 应用的类加载器,Web应用下的资源文件,class文件盒jar包,按照Java Web规范的标准,它们位于Web应用的/WEB-INF/classes和/WEB-INF/lib文件夹下。
3. 类加载器的实现
Tomcat类加载器其实有三个类实现:StandardClassLoader,WebappClassLoader和JasperLoader,这三个类加载器都是URLClassLoader的子类。不同的是,StandardClassLoader并没有客户化URLClassLoader方法,即,它也是采用委托的方式加载类的。而其他都覆写了loadClass()方法。
1. StandardClassLoader类加载器会创建Common类加载器的实例。
2. WebappClassLoader为每个应用创建类加载器实例,对于加载Web应用的类时,我们并非推荐使用父子委托模型,但是必须保证以java.*和javax.*开头的包必须由System类加载器加载,即最终由Bootstrap加载器加载。
核心代码如下:
public Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {
……
// (0) Check our previously loaded local class cache
clazz = findLoadedClass0(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}
// (0.1) Check our previously loaded class cache
clazz = findLoadedClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}
// (0.2) Try loading the class with the system class loader, to prevent
// the webapp from overriding J2SE classes
//保证以java.*和javax.*开头的包必须由System类加载器加载
try {
clazz = system.loadClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
// Ignore
}
……
boolean delegateLoad = delegate || filter(name);
// (1) Delegate to our parent if requested
//Mbeans加载时,是否采用delegate方式
if (delegateLoad) {
if (log.isDebugEnabled())
log.debug(" Delegating to parent classloader1 " + parent);
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
// (2) Search local repositories
//先本地加载,不委托父加载器加载
if (log.isDebugEnabled())
log.debug(" Searching local repositories");
try {
clazz = findClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Loading class from local repository");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
// 最后使用父加载器加载
if (!delegateLoad) {
if (log.isDebugEnabled())
log.debug(" Delegating to parent classloader at end: " + parent);
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
throw new ClassNotFoundException(name);
}
可以看到,并非简单的父子委托方式加载类
3. JasperLoader是为了加载jsp编译成的servlet而创建的类加载器,它覆写了loadClass()方法,除过加载org.apache.jsp.*的文件外,其他的均使用父加载器加载。
核心代码如下:
public Class loadClass(final String name, boolean resolve)
throws ClassNotFoundException {
Class clazz = null;
// (0) Check our previously loaded class cache
clazz = findLoadedClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
// (.5) Permission to access this class when using a SecurityManager
……
if( !name.startsWith(Constants.JSP_PACKAGE_NAME) ) {
// Class is not in org.apache.jsp, therefore, have our
// parent load it
clazz = parent.loadClass(name);
if( resolve )
resolveClass(clazz);
return clazz;
}
//所有的以org.apache.jsp.*开头的文件都由该类加载器加载。
return findClass(name);
}
今天就讲到这里了。
- 大小: 10.9 KB
分享到:
相关推荐
NULL 博文链接:https://yjhexy.iteye.com/blog/668334
3-7Tomcat中自定义类加载器的使用与源码实现(1).mp4
NULL 博文链接:https://davyjones2010.iteye.com/blog/2226286
很容易被反编译工具反编译,而传统的java源代码保护方法基本都是采用混淆的方式, 但这样会带来很多麻烦,而且也不能真正保护class文件, 本工具是对class文件进行加密,采用jni的方式解密运行, 加密算法达到256位...
很容易被反编译工具反编译,而传统的java源代码保护方法基本都是采用混淆的方式, 但这样会带来很多麻烦,而且也不能真正保护class文件, 本工具是对class文件进行加密,采用jni的方式解密运行, 加密算法达到256位...
JAVA CLASS文件加密工具是一款专门为保护您的JAVA源代码而设计的软件。传统的JAVA代码保护方式通常是扰乱生成的CLASS文件,从而降低反编译生成的源代码的可读性;有的保护工具甚至能生成部分废代码(垃圾代码),...
很容易被反编译工具反编译,而传统的java源代码保护方法基本都是采用混淆的方式, 但这样会带来很多麻烦,而且也不能真正保护class文件, 本工具是对class文件进行加密,采用jni的方式解密运行, 加密算法达到256...
很容易被反编译工具反编译,而传统的java源代码保护方法基本都是采用混淆的方式, 但这样会带来很多麻烦,而且也不能真正保护class文件, 本工具是对class文件进行加密,采用jni的方式解密运行, 加密算法达到256位...
众所周知,java编译后的class文件是一种中间字节字文件,很容易被反编译工具反编译,而传统的java源代码保护方法基本都是采用混淆的方式,但这样会带来很多麻烦,而且也不能真正保护class文件,本工具是对class文件...
简要介绍 JAVA CLASS文件加密工具是一款专门为保护您的JAVA源代码而设计的软件。传统的JAVA代码保护方式通常是扰乱生成的CLASS文件,从而降低反编译生成的源代码的可读性;有的保护工具甚至能生成部分废代码...
解决eclipse显示jar源代码中文乱码问题 ] () [ 使用 RMI + ZooKeeper 实现远程调用框架 ] () [ Java 注解指导手册 – 终极向导 ] () [ 轻量级分布式 RPC 框架 ] () [ 一个简单的guava cache 例子] () [ 你应该知道的...
运行加密项目时,无需求修改tomcat,spring等源代码。支持普通jar包、springboot jar包以及普通java web项目编译的war包。支持spring framework、swagger等需要在启动过程中扫描注解或生成字节码的框架。支持maven...
启用Tomcat的多连接器(Multiple Connectors) viii. 64.8. 在前端代理服务器后使用Tomcat ix. 64.9. 使用Jetty替代Tomcat x. 64.10. 配置Jetty xi. 64.11. 使用Undertow替代Tomcat xii. 64.12. 配置Undertow xiii....
但通常情况下,由于Java Bean是被容器所创建(如Tomcat)的,所以Java Bean应具有一个无参的构造器,另外,通常Java Bean还要实现Serializable接口用于实现Bean的持久性。Java Bean实际上相当于微软COM模型中的本地...