tomcat源码分析—类加载体系
分析Tomcat 的类加载机制之前,还来看看Java 体系的类加载器,在《深入理解Java虚拟机》书中讲到了Java的类加载机制
1:类加载机制
源码编译器将java源代码编译成字节码文件(class文件),字节码文件格式主要分为两部分:常量池和方法字节码。 具体查看 Java 类加载与初始化
java虚拟机中的类加载器将class文件加载到内存中,通过数据验证,解析,初始化等过程来创建j实例。
每个类加载器都有自己的命名空间,命名空间由该加载器及所有父加载器所加载的类组成,如果同一个class文件被两个不同的类加载器加载,那么通过这两个class也就不同的。
public class ClassLoaderTest {
public static void main(String[] args)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Product product = new Product(10, "apple");
System.out.println(product);
CustomClassLoader classLoader = new CustomClassLoader(null);
Class<?> class1 = classLoader.loadClass("com.java8.demo.Product");
System.out.println(class1.newInstance());
Product product1 = (Product) class1.newInstance();
System.out.println(product1.getClass());
System.out.println("END...");
}
public static class CustomClassLoader extends ClassLoader {
public CustomClassLoader(ClassLoader parent) {
super(parent);
}
@SuppressWarnings("resource")
private byte[] locaClassData(String name) {
byte[] bytes = new byte[256];
try {
name = name.replace(".", "/");
String fileName = "D:/java/workspace/demos/javacode-demo/target/classes/" + name + ".class";
FileInputStream inputStream = new FileInputStream(new File(fileName));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int len = 0;
while ((len = inputStream.read(bytes)) > 0) {
outputStream.write(bytes, 0, len);
}
outputStream.flush();
return outputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] bytes = locaClassData(name);
return defineClass(name, bytes, 0, bytes.length);
}
}
}
输出如下:
com.java8.demo.Product@15db9742
com.java8.demo.Product@70dea4e
Exception in thread "main" java.lang.ClassCastException: com.java8.demo.Product cannot be cast to com.java8.demo.Product
at com.java8.demo.ClassLoaderTest.main(ClassLoaderTest.java:18)
红色部分可以看出,虽然是同一个class文件,但是通过不同的类加载器生成的类不同。
2: 双亲委派机制
Java虚拟机规范中提到的主要有3个类加载器
1:启动类加载器(Bootstrap ClassLoader):这个类加载器加载JAVA_HOME/lib目录中的,或者由-Xbootclasspath参数指定的路径中的jar文件。
2:扩展类加载器(Extension ClassLoader):加载 JAVA_HOME/lib/ext目录下的,或者由System.getProperty("java.ext.dirs")指定的路径中的jar,开发者可以直接使用扩展类加载器。在 使用Java运行程序时,也可以指定其搜索路径,例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld。
3:应用程序类加载器(Application ClassLoader): 也称系统类加载器,应用程序加载器实现了sun.misc.Launcher$AppClassLoader,它负责加载系统类路径java -classpath或-D java.class.path 指定路径下的类库,也就是我们经常用到的classpath路径,开发者可以直接使用系统类加载器。一般情况下该类加载是程序中默认的类加载器,通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器。
类加载器的关系图如下:

双亲委派机制的加载过程:
3: Tomcat的类加载体系
tomcat中的类加载除了jvm 规范提到的以上三种类加载器之外,还实现了自身的类加载体系。下图展示了Tomcat的类加载体系,上下类加载器之间不是继承关系,而是一种委派关系
/common/*、/server/*、/shared/*和/WebApp/WEB-INF/*中的Java类库。shared.loader="${catalina.base}/shared/lib","${catalina.base}/shared/lib/*.jar"

浙公网安备 33010602011771号