Java命令执行代码流程
当用Java命令去运行一个Class文件时,执行流程如下:
loadClass类加载过程由一下几步组成:
类被加载到方法区中,主要包含:
-
运行时常量池
-
类型信息
-
字段信息
-
方法信息
-
类加载的引用
加载这个类的ClassLoader实例的引用
-
对应Class实例的引用
对应堆中Class类型的对象实例,比如com.xxx.Class.class,作为访问方法区中类定义的入口。
类加载器
Java里面有一下几种类加载器:
- 引导类加载器:负责加载支持JVM运行的jre的lib目录下的核心jar包,比如rt.jar;
- 扩展类加载器:负责加载支持JVM运行的jre的lib目录下ext扩展目录的jar包;
- 应用程序加载器:负责加载ClassPath路径下的包,主要是加载自己写的类;
- 自定义类加载器:负责加载用户自定义目录下的jar或者class文件;
类加载器初始化过程
在Launcher的构造方法中,创建了两个类加载器,分别是ExtClassLoader扩展类加载器,AppClassLoader应用类加载器。
默认使用Launcher#getClassLoader()返回类加载器AppClassLoader加载应用程序。
自定义类加载器
只需要继承java.lang.ClassLoader类,重写其findClass()即可。
双亲委派机制
简单说就是在加载类的时候,先由父类加载器加载,如果父类加载的加载路径下找不到目标Class,则在自己的类加载路径下查找Class,并加载类。
为什么要有双亲委派机制呢?
- 安全机制:防止Java核心API被修改;
- 避免类重复加载:当父类加载器已经加载该类时,子类加载器就没必要在加载了,保证被加载类的唯一性;
全盘委托机制
指的是当一个Class被ClassLoader加载时,这个Class所依赖的类都将由这个ClassLoader加载,除非显式的使用另外一个ClassLoader。
打破双亲委派机制
只需要继承ClassLoader,重写findClass()和loadClass()方法
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadByte(name);
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}
/**
* 重写类加载方法,实现自己的加载逻辑,不委派给双亲加载
*/
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) {
long t1 = System.nanoTime();
//非自定义的类走双亲委派
if (!name.startsWith("com.xxx.jay")){
c = this.getParent().loadClass(name);
}else{
c = findClass(name);
}
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
}
为什么要打破双亲委派机制
以Tomcat为例,以下问题使用默认的双亲委派机制不能解决:
- 部署两个应用程序,应用程序依赖同一个类库的不同版本,同名不同版本的类库都需要加载,默认的双亲委派机制不能实现;
- 部署在同一个Web容器中的应用依赖的相同类库的相同版本可以共享,不然部署一个应用就需要加载一套类库;
- JSP热加载,JSP编译成Class文件后,如果使用默认的双亲委派机制,修改后的JSP不会被加载,因为已经加载过了,会从方法区中找到。所以需要卸载掉修改的JSP文件,这样就可以实现JSP热加载。