类加载运行全过程
其中loadClass的类加载过程有如下几步
加载 ==> 验证 ==> 准备 ==> 解析 ==> 初始化 ==> 使用 ==> 卸载
加载: 通过IO读入其字节码 使用到该类是才会加载在堆中生成Class对象 作为方法区入口
验证: 校验字节码文件的准确性
准备: 给类的静态变量分配内存 并赋初值
解析: 将符号引用转为直接引用 (静态链接)
初始化: 对类的静态变量初始化为指定值 执行静态代码块
注: 类被加载到方法区中包含 运行是常量池、类型信息、字段信息、方法信息、类加载器的引用、对应class实例引用等信息
双亲委派机制
引导类加载器(Bootstrap)用于加载jre/lib/下的核心jar
扩展类加载器(Extension)用于加载jre/lib/ext/下的jar
应用程序类加载器(AppClassLoader)Java也叫系统类加载器,加载当前应用的classpath的所有类
用户自定义加载器 Java.lang.ClassLoader的子类,用户可以定制类的加载方式
JVM默认使用Launcher.getClassLoader()方法返回的加载器AppClassLoader实例加载我们的应用程序
public class Launcher {
private static URLStreamHandlerFactory factory = new Factory();
private static Launcher launcher = new Launcher();
private static String bootClassPath = System.getProperty("sun.boot.class.path");
private ClassLoader loader;
private static URLStreamHandler fileHandler;
public static Launcher getLauncher() {
return launcher;
}
public Launcher() {
ExtClassLoader var1;
try {
//扩展类加载器 构造过程中将其父加载器设为null
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
//应用类加载器 构造过程中将其父加载器设为ExtClassLoader
//并且loader为AppClassLoader 默认使用AppClassLoader加载应用程序
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
Thread.currentThread().setContextClassLoader(this.loader);
String var2 = System.getProperty("java.security.manager");
if (var2 != null) {
SecurityManager var3 = null;
if (!"".equals(var2) && !"default".equals(var2)) {
try {
var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
} catch (IllegalAccessException var5) {
} catch (InstantiationException var6) {
} catch (ClassNotFoundException var7) {
} catch (ClassCastException var8) {
}
} else {
var3 = new SecurityManager();
}
if (var3 == null) {
throw new InternalError("Could not create SecurityManager: " + var2);
}
System.setSecurityManager(var3);
}
}
}
ClassLoader.loadClass()方法实现了双亲委派机制
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 检查当前类加载器是否已经加载了该类
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
//如果当前类加载器父加载器!=null则委托父加载器加载该类
c = parent.loadClass(name, false);
} else {
//如果当前类加载器父加载器==null则委托引导类加载器加载该类
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
if (c == null) {
long t1 = System.nanoTime();
//调用URLClassLoader.findClass()在加载器的类路径里查找并加载该类
c = findClass(name);
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
自定义类加载器
public class YanClassLoader extends ClassLoader{
private String classPath;
public YanClassLoader(String classPath) {
this.classPath = classPath;
}
private byte[] loadByte(String name) throws Exception {
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classPath + "/" + name
+ ".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
}
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();
}
}
/**
* 重写类加载方法,实现自己的加载逻辑,不委派给双亲加载
* @param name
* @param resolve
* @return
* @throws ClassNotFoundException
*/
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
synchronized (getClassLoadingLock(name)) {
Class<?> c = findLoadedClass(name);
if (c == null) {
long t1 = System.nanoTime();
//非自定义的类还是走双亲委派加载
if (!name.startsWith("com.yan.jvm")){
c = this.getParent().loadClass(name);
}else{
c = findClass(name);
}
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
}