java指令到底干了些什么?我们些的java代码是如何被加载到jvm内存中执行的?
实现自定义的类加载器。实现自己的热加载。实现同类多个版本共存。
类加载具有五个阶段:加载、验证、准备、解析、初始化
加载:将java中的class字节文件加载进入堆内存中。
验证:验证该类是否正确,class文件不能对虚拟机造成危害,验证文件格式,元数据,字节码,符号引用验证。
准备:java类中又许多其他变量,变量分为两种,一种是类变量,一种是实例变量,类变量就是具有static定义的变量。这时候需要根据定义类型去开辟空间准备。
int 默认是0,long默认是0L等等。无论类中打算赋值多少。都先准备初始值。
解析:主要是将虚拟机常量池中的符号引用转为直接引用。
初始化:将在准备阶段准备好的变量。在这里根据java类的定义,赋值。
java的类加载机制:
java的类加载体系:BootStrao classloder > ExtclassLoader->Appclassloader
BootStrao classloder(启动类加载器):底层采用c++实现,主要是加载jdk\jre\lib自带的类库,不能直接引用。
ExtclassLoader(扩展类加载器):负责加载jdk\jre\lib\ext中,或者系统知道路径的类库。开发中可以使用该加载器
Appclassloader(应用程序加载器):负责加载ClassPath应用程序的所有指定的类。可以直接使用。
每种类加载器都有他自己的加载目录。
双清委派:一个类java加载进jvm的过程
每个类加载器对他加载过的类都有一个缓存。
向上委托查找,向下委托加载。
描述:一个类如果需要加载,首先会让Appclassloader进行加载,Appclassloader会先去自己的缓存中查找,如果没有。
委托给自己的上一级ExtclassLoader加载,ExtclassLoader又回去自己的缓存中查找,如果没有继续委托给上级BootStrao classloder。
这时候如果BootStrao classloder还是没有,会去自己的加载目录里面进行查询加载,如果目录里面没有委托给自己下级ExtclassLoader。
ExtclassLoader就也会去自己的加载目录加载,如果还是没有再委托给下级Appclassloader进行加载。Appclassloader也去自己的加载目录里找。
如果没有找到,出现异常,没有该类。 这个流程中只有有一步找到就停下来。
目的是:对JDK中的类进行保护,防止覆盖。
JDK中还有沙箱保护机制进行保护。就是包名不能是JDK一样的包目录。
JDK的类加载对象:
ClassLoader->SecureClassLoader->URLclassLoader->ExtclassLoader,AppClassLoader
代码拆分:
可以通过URLclassLoader调用远程JAR包,这时候可以使用反射的方式,指定反射类调用对应的方法,或者创建对象。
jar包混淆:
需要自定义类加载器。可以实现SecureClassLoader接口
重写findClass方法,读取字节码,拿到字节码以后。调用defineClass方法.就可以实现
就可以加载其他文件的编码代码了,不一定需要是class文件。
可以通过对二进制文件,字节码进行简单的混淆,做少量的修改,这样class安全性得到提升。
热加载:
java里的每一个类加载器,对他加载过的类,都会保留一个缓存没。正是这个缓存,导致我们无法实现热加载。
可以通过每次new一个SalarylartLoader的方式,实现热加载。
缺点:因为热加载机制有一个加载的过程,很容易出错,还有一个更大的问题是,热加载必然产生非常多的垃圾对象。
在ClassLoader的loadClass方法中,还加入了一个布尔参数
热加载机制,可以在编译中能发现的问题,全都到了运行时中,会对程序照成很大影响。
打破双亲委派机制
有可能写了类加载过程中,本地代码中又不小心写了一个同样的类,这时候双亲委派机制,会优先加载本地代码。而不是jar包中的代码。
通过打破双亲委派机制,我们可以实现需要加载的类优先从jar包中加载,而不是本地代码类。
打破双亲委派后,出现问题,会加载出两个类,而且这两个类的类型无法转换。
总结:
java类加载机制,是jdk源码像JVM底层学习的一个门户。
实现的类加载流程,模拟的tomcat的类加载机制。
spi机制,jdbc.