JVM 自定义类加载器在复杂类情况下的运行分析
一、自定义类加载器在复杂类情况下的运行分析
1、使用之前创建的类加载器
public class MyTest16 extends ClassLoader{
private String className;
//目录
private String path;
private final String fileExtension = ".class";
public MyTest16(String classLoadName){
super(); //将系统类加载器当做该类加载器的父加载器
this.className = classLoadName;
}
public MyTest16(ClassLoader parent, String classLoadName){
super(parent); //显示指定该类加载器的父加载器器
this.className = classLoadName;
}
public void setPath(String path) {
this.path = path;
}
@Override
public String toString() {
return "[" + this.className + "]";
}
@Override
protected Class<?> findClass(String clasName) throws ClassNotFoundException {
System.out.println("findClass invoked:" + clasName);
System.out.println("class loader name: " + this.className);
byte[] data = this.loadClassData(clasName);
return this.defineClass(clasName,data, 0, data.length);
}
private byte[] loadClassData(String className){
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = null;
try{
className = className.replace(".","//");
//System.out.println("className:" +this.className);
is = new FileInputStream(new File(this.path + className + this.fileExtension));
baos = new ByteArrayOutputStream();
int ch = 0;
while ( -1 != (ch = is.read())){
baos.write(ch);
}
data = baos.toByteArray();
}catch (Exception ex){
ex.printStackTrace();
}finally {
try {
is.close();
baos.close();
}catch (Exception ex){
ex.printStackTrace();
}
}
return data;
}
}
2、创建MyCat类
public class MyCat {
public MyCat(){
System.out.println("MyCat is loaded by:" + this.getClass().getClassLoader());
}
}
3、创建MySample类
public class MySample {
public MySample(){
System.out.println("MySample is loaded by:" + this.getClass().getClassLoader());
new MyCat();
}
}
4、创建测试类
public class MyTest17 {
public static void main(String[] args) throws Exception{
MyTest16 loader1 = new MyTest16("loader1");
Class<?> clazz = loader1.loadClass("com.example.jvm.classloader.MySample");
System.out.println("class:" + clazz.hashCode());
//如果注释掉改行,那么并不会实例化MySample对象,即MySample构造方法不会被调用
//因此不会实例化MyCat对象,即没有对MyCat进行主动使用,这里就不会加重MyCat Class
Object object = clazz.newInstance();
}
}
打印结果
class:1735600054
MySample is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
增加-XX:+TraceClassLoading后的打印结果

如果去掉Object object = clazz.newInstance();
打印结果为

说明:如果注释掉Object object = clazz.newInstance();该行,那么并不会实例化MySample对象,即MySample构造方法不会被调用
因此不会实例化MyCat对象,即没有对MyCat进行主动使用,这里就不会加载MyCat Class。
而且这个例子说明MyCat没有被预先加载
二、对一的Code进行改造
在一的基础上,新建一个测试类
public class MyTest17_1 {
public static void main(String[] args) throws Exception{
MyTest16 loader1 = new MyTest16("loader1");
loader1.setPath("D:/temp/");
Class<?> clazz = loader1.loadClass("com.example.jvm.classloader.MySample");
System.out.println("class:" + clazz.hashCode());
//如果注释掉该行,那么并不会实例化MySample对象,即MySample构造方法不会被调用
//因此不会实例化MyCat对象,即没有对MyCat进行主动使用,这里就不会加载MyCat Class
Object object = clazz.newInstance();
}
}
里面增加了一个方法loader1.setPath("D:/temp/");
然后将MyCat.class 和MySample.class 剪切到D:/temp/目录下,如下面两图


打印结果:
findClass invoked:com.example.jvm.classloader.MySample
class loader name: loader1
class:2133927002
MySample is loaded by:[loader1]
findClass invoked:com.example.jvm.classloader.MyCat
class loader name: loader1
MyCat is loaded by:[loader1]
三、类加载命名空间
在二的基础上,MyCat.java 增加一行代码System.out.println("from MyCat:" + MySample.class);
public class MyCat {
public MyCat(){
System.out.println("MyCat is loaded by:" + this.getClass().getClassLoader());
System.out.println("from MyCat:" + MySample.class);
}
}
然后重新build,打印结果如下:
class:1735600054
MySample is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
from MyCat:class com.example.jvm.classloader.MySample
现在将build路径下的classloader文件夹拷贝到D:\temp\com\example\jvm\classloader下,删除build路径下的MySample.class
打印输出结果:
findClass invoked:com.example.jvm.classloader.MySample
class loader name: loader1
class:2133927002
MySample is loaded by:[loader1]
MyCat is loaded by:sun.misc.Launcher$AppClassLoader@18b4aac2
Exception in thread "main" java.lang.NoClassDefFoundError: com/example/jvm/classloader/MySample
at com.example.jvm.classloader.MyCat.<init>(MyCat.java:10)
at com.example.jvm.classloader.MySample.<init>(MySample.java:10)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at com.example.jvm.classloader.MyTest17_1.main(MyTest17_1.java:16)
Caused by: java.lang.ClassNotFoundException: com.example.jvm.classloader.MySample
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 8 more
说明:MySample由自定义loader加载,MyCat由AppClassLoader。两个类是不同的loader加载,处于不同的命名空间。
所以System.out.println("from MyCat:" + MySample.class); 抛出异常。 子加载器所加载的类能够访问父加载器所加载的类。反之,父加载器所加载的类无法访问子加载器所加载的类
JVM 自定义类加载器在复杂类情况下的运行分析的更多相关文章
- JVM自定义类加载器加载指定classPath下的所有class及jar
一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...
- (转)JVM——自定义类加载器
背景:为什么要自定义,如何自定义,实现过程 转载:http://blog.csdn.net/SEU_Calvin/article/details/52315125 0. 为什么需要自定义类加载器 网上 ...
- JVM——自定义类加载器
)以上两种情况在实际中的综合运用:比如你的应用需要通过网络来传输 Java 类的字节码,为了安全性,这些字节码经过了加密处理.这个时候你就需要自定义类加载器来从某个网络地址上读取加密后的字节代码,接着 ...
- JVM 自定义类加载器
一.创建自定义类加载器 package com.example.jvm.classloader; import java.io.ByteArrayOutputStream; import java.i ...
- 4.自定义类加载器实现及在tomcat中的应用
了解了类加载器的双亲委派机制, 也知道了双亲委派机制的原理,接下来就是检验我们学习是否扎实了,来自定义一个类加载器 一. 回顾类加载器的原理 还是这张图,类加载器的入口是c++调用java代码创建了J ...
- jvm(1)类的加载(二)(自定义类加载器)
[深入Java虚拟机]之四:类加载机制 1,从Java虚拟机的角度,只存在两种不同的类加载器: 1,启动类加载器:它使用C++实现(这里仅限于Hotspot,也就是JDK1.5之后默认的虚拟机,有其他 ...
- Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论
Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...
- JVM性能优化--类加载器,手动实现类的热加载
一.类加载的机制的层次结构 每个编写的".java"拓展名类文件都存储着需要执行的程序逻辑,这些".java"文件经过Java编译器编译成拓展名为". ...
- 【Java虚拟机8】自定义类加载器、类加载器命名空间、类的卸载
前言 学习类加载器就一定要自己实现一个类加载器,今天就从一个简单的自定义类加载器说起. 自定义类加载器 例1 一个简单的类加载器,从一个给定的二进制名字读取一个字节码文件的内容,然后生成对应的clas ...
随机推荐
- React系列,初识
学习react对于新手来说,还没有学react往往就会被webpack,npm等搞的晕头转向,所以我们今天就从最简单的方式入手 <script src="react.js"& ...
- 在线研讨会预热 | 基于ASPICE&CNAS的单元测试介绍
随着新能源车.智能驾驶技术的快速发展,软件本身复杂度越来越高,应用场景也是复杂多样,如何保证软件质量对我们来说是一个严峻的挑战.软件测试作为软件质量保证的重要手段,被各大整车厂和供应商 ...
- brief 程序注释
/** * @brief Acceleration (g's) in body frame. * Embedded MPL defines gravity as positive accelerati ...
- CH6302 雨天的尾巴
6302 雨天的尾巴 0x60「图论」例题 背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了 ...
- c语言1博客作业08
一.本周作业头 这个作业属于那个课程 C语言程序设计II 这个作业要求在哪里 http://edu.cnblogs.com/campus/zswxy/SE2019-3/homework/9982 我在 ...
- Mycat简单配置
最近项目中需要用到Mycat来作为Mysql的分表中间件.所以稍微研究了一下. Mycat使用起来是非常方便,而且最重要的是配置简单,稍显麻烦的就是需要对库中的每一个表都进行配置. 记录一下最重要的几 ...
- 洛谷-P2661 信息传递——有向图中的最小环
题意 给定一个 $n$ 个结点有向图,求其中最小环的大小.($n \leq 200000$). 分析 由于每条点出度都为1且满足传递性,可以用并查集做. 如果有一条从x到y的有向边,那么y就是x的父亲 ...
- 洛谷 P3375 【模板】KMP字符串匹配 题解
KMP模板,就不解释了 #include<iostream> #include<cstdio> #include<cstring> #include<algo ...
- Kubernetes 学习18配置网络插件flannel
一.概述 1.我们在学习docker时知道docker有四种常用的网络模型 a.bridge:桥接式网络 b.joined:联盟式网络,共享使用另外一个容器的网络名称空间 b.opened:容器直接共 ...
- js之大文件断点续传
文件夹上传:从前端到后端 文件上传是 Web 开发肯定会碰到的问题,而文件夹上传则更加难缠.网上关于文件夹上传的资料多集中在前端,缺少对于后端的关注,然后讲某个后端框架文件上传的文章又不会涉及文件夹. ...