1.Class装载验证流程
一个对car类的run方法的符号引用,它由run方法的全名和相关描述符组成,在解析阶段,java虚拟机会把这个符号引用替换成一个指针,指针指向car类的run方法在方法区的内存位置,指针就是直接引用
2.什么是类加载器---ClassLoader
3.JDK中ClassLoader默认设计模式
自底向上调用findLoadedClass
自顶向下调用parent.loadClass
4.打破常规模式
顶层的类加载器无法看到底层的类加载器的相关信息
所以如何解决下面的问题呢?
通过Thread.setContextClassLoader()
static private Class> getProviderClass(String className, ClassLoader cl,
boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException
{
try {
if (cl == null) {
if (useBSClsLoader) {
return Class.forName(className, false, FactoryFinder.class.getClassLoader());
} else {
cl = ss.getContextClassLoader();
if (cl == null) {
throw new ClassNotFoundException();
}
else {
return Class.forName(className, false, cl);
}
}
}
else {
return Class.forName(className, false, cl);
}
}
catch (ClassNotFoundException e1) {
if (doFallback) {
// Use current class loader - should always be bootstrap CL
return Class.forName(className, false, FactoryFinder.class.getClassLoader());
}
else {
throw e1;
}
}
}
该方法是在rt.jar/javax/xml/parsers/FactoryFinders.class中的方法。展示如何在bootstrap加载器中加载apploader的类
CL是一个上下文加载器,可以突破父委托机制的限制,
forName(String name, boolean initialize, ClassLoader loader) 使用给定的类加载器返回与给定字符串名称的类或接口相关联的类对象,如果loader为空,则使用bootstrap加载器进行加载。如果传入的CL是app加载器,那么就返回使用app加载器进行加载的类对象。突破父委托机制的限制。
父委托机制的破坏
破坏父委托机制的例子
重写loadClass方法;先从底层ClassLoader加载
①查找类是否已经被加载,findloadedclass
②找不到,读文件通过IO读入到byte数组,然后通过defineClass定义类,将字节数组转换成类的实例,属于类的加载。
FileNotFound原因是DemoA这个类没有声明任何父类,默认是Object为父类;所以在加载DemoA之前,先加载父类Object,改写loadClass之后,自底向上加载类,即使用OrderClassLoader加载Object,但是在OrderClassLoader中,找不到Object.class文件,而Object.class在rt.jar中,因此抛出异常,请求父类加载器,右上图绿色指出使用apploader加载Object。Object.class是在rt.jar中,应该使用bootstrap进行加载的,这里有点想不通; 之后,就可以顺利加载DemoA了
5.热替换
然后再DoopRun运行过程中,将CVersionA.java做如下修改
得到的class文件,覆盖掉原来的class文件,输出发生改变