探索JVM底层奥秘ClassLoader源码分析
1、JVM基本结构:
*.java--------javac编译------>*.class-----ClassLoad加载---->运行时数据区------->执行引擎,接口库------>本地方法库
2、JVM运行流程:
public class Dome {
private static int tem=1;
static {
tem=2;
System.out.println(tem);
}
public static void main(String[] args) {
tem=6;
System.out.println(tem);
}
}
类的装载:
加载,连接(验证,准备,解析),初始化,使用,卸载
Class会保存类的定义或者结构到堆中
初始化:执行类的构造器《clinit》,为类的静态变量赋予正确的初始值
构造器:
1、static变量
2、Static{}语句块
构造方法:实列化对象
3、类加载器双亲委派模型
Bootstrat ClassLoader :启动类加载器(C++,内核)【rt.jar】 null
Extension ClassLoader:扩展类加载器---extends->【%JAVA_HOME%/lib/ext/*.jar】ClassLoader
App ClassLoader:系统类加载器 ----extends-->【Classpath下加载】ClassLoader(扩展类加载器)
自定义类加载器: extends ClassLoader(系统类加载器 )---【自定义加载】
public static void main(String[] args) {
//System.out.println(Dome2.class.getClassLoader());
ClassLoader classLoader=Dome2.class.getClassLoader();
while(classLoader!=null) {
System.out.println(classLoader);
classLoader=classLoader.getParent();
}
System.out.println(classLoader);
}
编译:
sun.misc.Launcher$AppClassLoader@2a139a55 》系统类加载器
sun.misc.Launcher$ExtClassLoader@7852e922 》扩展类型加载器
Null 》启动类加载器
在jdk的rt.jar下找到java.lang.classLoader类,找到类加载方法:
@parem:name,类的二进制字节流
public Class<?> loadClass(String name) throws ClassNotFoundException{
return loadClass(name, false);
}
查找是否有这个类:
有:从父类中加载
无:从BootstrapClass加载
//parent:
// The parent class loader for delegation
// Note: VM hardcoded the offset of this field, thus all new fields
// must be added *after* it
private final ClassLoader parent;//父类委派机制 :包含关系
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name); //自定义类加载【回调方法】
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
被子类重写:
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
实列:自定义类加载器
一个本地的Demo.class文件,一个编译环境中的Demo.class文件
测试调用类:
public class Dome {
public Dome() {
System.out.println("A Dome:"+Dome.class.getClassLoader());
}
}
需求实现类:
package com.cn.classload;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @Description: 自定义类加载器
* @ClassName: MyClassLoader
* @author 明
* @date 2019年9月15日
*
*/
public class MyClassLoader extends ClassLoader {
private String path;// 加载类的路劲
private String name;// 类加载器名称
public MyClassLoader(String name, String path) {
super();// 让系统类加载器成为该类的父类
this.name = name;
this.path = path;
}
// 父类委托机制:父类加载器
public MyClassLoader(ClassLoader parent, String name, String path) {
super(parent);
this.name = name;
this.path = path;
}
/**
* 加载自定义的ClassLoader Title: findClass Description:
*
* @param name:包路径
* @return
* @throws ClassNotFoundException
* @see java.lang.ClassLoader#findClass(java.lang.String)
*
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = readClassFileToByteArray(name);
return this.defineClass(name, data, 0, data.length);
}
/**
* Title: toString Description:
*
* @return
* @see java.lang.Object#toString()
*
*/
@Override
public String toString() {
// TODO Auto-generated method stub
return this.name;
}
/**
* @Description: 获取.class文件的字节数组
* @Title: readClassFileToByteArray
* @date 2019-09-15 17:27
* @param @param name2
* @param @return 参数
* @return byte [] 返回类型
* @throws @return byte []
* @param name2
* @return
*/
private byte[] readClassFileToByteArray(String name) {
InputStream iStream = null;
byte[] returnData = null;
name = name.replaceAll("\\.", "/");
String filePath = this.path + name + ".class";
System.out.println("路径:"+filePath);
File file = new File(filePath);
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
iStream = new FileInputStream(file);
int tmp = 0;
while ((tmp = iStream.read()) != -1) {
os.write(tmp);
}
returnData = os.toByteArray();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (iStream != null) {
try {
iStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return returnData;
}
}
测试类:
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
MyClassLoader zhangfeimyClassLoader=new MyClassLoader("zhangfei","D:/com/cn/classload/");
//MyClassLoader wukongmyClassLoader=new MyClassLoader(zhangfeimyClassLoader,"wukong","D:/com/cn/classload/");//现在张飞是悟空的父类委派加载器(输出的就是编译环境中的Dome.class文件)
MyClassLoader wukongmyClassLoader=new MyClassLoader(null,"wukong","D:/com/cn/classload/");//这里父类没有就是用自定义的加载器(输出的就是本地磁盘上的Dome.class文件)
Class<?> c=wukongmyClassLoader.loadClass("Dome");
c.newInstance();
}
探索JVM底层奥秘ClassLoader源码分析的更多相关文章
- 别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】
目录 1.什么是类的加载(类初始化) 2.类的生命周期 3.接口的加载过程 4.解开开篇的面试题 5.理解首次主动使用 6.类加载器 7.关于命名空间 8.JVM类加载机制 9.双亲委派模型 10.C ...
- JVM 类加载器ClassLoader源码学习笔记
类加载 在Java代码中,类型的加载.连接与初始化过程都是在程序运行期间完成的. 类型可以是Class,Interface, 枚举等. Java虚拟机与程序的生命周期 在如下几种情况下,Java虚拟机 ...
- 探索drf执行流程之APIView源码分析
Django REST framework 简介 现在新一代web应用都开始采用前后端分离的方式来进行,淘汰了以前的服务器端渲染的方式.而实现前后端分离是通过Django REST framework ...
- ClassLoader源码分析与实例剖析
在之前已经对类加载器做了不少实验了,这次主要是来分析一下ClassLoader的源码,当然主要是先从理解官方给它的注释开始,为之后自定义类加载器打好坚石的基础,下面开始: 而从类的层次结构来看也能感受 ...
- Redis学习之底层链表源码分析
Redis底层链表的源码分析: 一.链表结点的结构(单个结点): // listNode 双端链表节点 typedef struct listNode { // 前置节点 struct listNod ...
- JAVA ArrayList集合底层源码分析
目录 ArrayList集合 一.ArrayList的注意事项 二. ArrayList 的底层操作机制源码分析(重点,难点.) 1.JDK8.0 2.JDK11.0 ArrayList集合 一.Ar ...
- [软件测试]网站压测工具Webbench源码分析
一.我与webbench二三事 Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能.Webbench ...
- 网站(Web)压测工具Webbench源码分析
一.我与webbench二三事 Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能.Webbench ...
- [五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的
Launcher启动类 本文是双亲委派机制的源码分析部分,类加载机制中的双亲委派模型对于jvm的稳定运行是非常重要的 不过源码其实比较简单,接下来简单介绍一下 我们先从启动类说起 有一个Lau ...
随机推荐
- 解决在manjaro下,vscode无法将chrome作为默认浏览器打开
Same issue. The solution is simple. Find the name of the exec command, for google chrome in arch lin ...
- Kubernetes 监控方案之 Prometheus Operator(十九)
目录 一.Prometheus 介绍 1.1.Prometheus 架构 1.2.Prometheus Operator 架构 二.Helm 安装部署 2.1.Helm 客户端安装 2.2.Tille ...
- Jenkins通过完全复制快速创建新项目
- [05]Go设计模式:建造者模式(Builder Pattern)
目录 建造者模式 一.简介 二.代码 三:参考资料 建造者模式 一.简介 建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象.这种类型的设计模式属于创建型模式, ...
- Python Tkinter 文本框(Entry)
Python Tkinter 文本框用来让用户输入一行文本字符串. 你如果需要输入多行文本,可以使用 Text 组件. 你如果需要显示一行或多行文本且不允许用户修改,你可以使用 Label 组件. 语 ...
- Oracle和Mysql中的字符串的拼接
SQL允许两个或者多个字段之间进行计算,字符串类型的字段也不例外.比如我们需要 以"工号+姓名"的方式在报表中显示一个员工的信息,那么就需要把工号和姓名两个字符 串类型的字段拼接计 ...
- 八、spring生命周期之BeanPostProcessor
BeanPostProcessor我们一般称为Bean的后置处理器,它与我们前面介绍的InitialingBean.init-method等一样,都是在bean的初始化时被调用,具体的用法我们在举例中 ...
- web动静分离
1 动态资源和静态资源 动态资源:多次访问页面,原代码会发生改变,比如jsp 静态资源:多次访问页面,原代码不发生改变,比如html,css 2 动静分离 将动态资源(jsp)放在tomcat服务器中 ...
- 下载 m3u8 直播流的方法
下载 FFmpeg http://ffmpeg.org/download.html 查找直播流地址 找到目标视频对应的 m3u8 播放列表. 执行脚本 ffmpeg -i https://nhkmov ...
- django RetrieveModelMixin 查询字段替换
mixins 中RetrieveModelMixin 获取当个实例 其中的主键pk获取,可以通过lookup_field 如:要换成用username字段进行查询 注:替换的字段要有唯一约束 look ...