宏观运行java com.tuling.jvm.Math.class命令后执行的流程
底层C++调用sun.misc.launcher.getlauncher()方法,获取launcher对象,jvm全局唯一对象,同时会初始化好以下的类加载器,每个加载器的加载类的路径·是不一样的
1.引导类加载器(bootstapClassLoader)
c语言实现,加载jre的lib包的基础核心类库jar包
2.扩展类加载器(extClassLaoder)
java实现,加载jre的lib包下ext扩展目录jar包
3.应用类加载器(appClassLoader)
java实现,加载自己写的java字节码文件
3.自定义类加载器
所有类加载器都会调用到ClassLoader这个类的laodClass方法 因为引导类加载器bootstapClassLoader是顶级父加载器c语言编写 , 所以只有应用类加载器(appClassLoader)
getParent才会是null,应用类加载器(appClassLoader) 以及自己实现的的子类加载器 getParent才会有值,findLoadedClass会查询当前类加载器是否已经加载过准备加载的这个类
加载类的主要流程在classLoader.loadClass(“全类名”);
双亲委派机制:
为什么一定从AppClassLoader开始加载?
因为源码launcher.getClassLoader()方法返回就是appClassLoader
为什么使用双亲委派机制?
如果直接从上到下依次执行bootstapClassLoader→extClassLaoder→appClassLoader加载类
有人伪造java.lang.String类,那么bootstrapClassLoader会加载lib下的java.lang.String类,appClassLoader也会加载一次伪造的java.lang.String类 那么就会造成安全隐患
避免重复加载lib和ext中的类
自定义类加载器
自定义加载器通常应用场景:
1.加密:java代码很容易被反编译,如果你需要把自己的代码进行加密,可以先将编译后的代码用某种加密算法加密,然后实现自己的类加载器,负责将这段加密后的代码还原。
2.从非标准的来源加载代码:例如你的部分字节码是放在数据库中甚至是网络上的,就可以自己写个类加载器,从指定的来源加载类。
3.动态创建:为了性能等等可能的理由,根据实际情况动态创建代码并执行。
只需要继承java.lang.ClassLoader类即可,两个核心方法,loaderClass(String,boolean)已经实现双亲委派机制 findClass()方法 默认空实现,需要重写findCalss(String)方法 测试记得把C的字节码放在相应的目录下并且删除当前idea中的C.java 和C.class文件 由于自定义的类加载器的父加载器是AppClassLoader 否则由于双亲委派还是显示AppClassLoader加载的C类
为什么自定义类加载器的父加载器是AppClassLoader?
因为自定义类加载器继承自ClassLoader,所以先初始化ClassLoader父加载器,而ClassLoader中的private final ClassLoader parent;parent属性赋值由Launcher类中sun.misc.launcher.getlauncher()执行时赋值
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)