探索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 ...
随机推荐
- MUD游戏开发教程视频
MUD游戏开发教程视频 https://space.bilibili.com/476328540/channel/detail?cid=91187
- 取消Windows server 2008关机提示备注的方法
打开“开始”-“运行”,在“打开”一栏中输入“gpedit.msc”命令打开组策略编辑器,依次展开“计算机配置”→“管理模板”→“系统”,双击右侧窗口出现的“显示‘关闭事件跟踪程序’”,将“未配置”改 ...
- [LeetCode] 516. Longest Palindromic Subsequence 最长回文子序列
Given a string s, find the longest palindromic subsequence's length in s. You may assume that the ma ...
- ehcache和redis的区别及适用场景
区别: (1)Redis 独立程序,是通过socket访问到缓存服务,效率比ecache低,比数据库要快很多,处理集群和分布式缓存方便,有成熟的方案 (2)Ehcache 直接在jvm虚拟机中缓存,速 ...
- 「模拟赛20191019」A 简单DP
题目描述 给一个\(n\times m\)的网格,每个格子上有一个小写字母. 对于所有从左上角\((1,1)\)到右下角\((n,m)\)只向下或向右走的路径构成的集合,判断是否存在两条走法不同的路径 ...
- 08 Spring框架的概念、优势、体系结构、耦合性和IOC(反转控制)
1.spring介绍 Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control: 反转控制)和 AOP(Aspect ...
- Integer的parseInt和valueOf的区别
先来看一下下面这段代码 String s = "1"; System.out.println(Integer.valueOf(s)); System.out.println(Int ...
- 关于MSVCR100.dll、MSVCR100d.dll、Msvcp100.dll、abort()R6010等故障模块排查及解决方法
一.常见故障介绍 最近在开发相机项目(项目细节由于公司保密就不介绍了),程序运行5个来月以来首次出现msvcr100.dll故障等问题,于是乎开始了分析之路,按照度娘上的一顿操作,期间也是出现了各种不 ...
- stm32F103片上串口USART1通信实验
硬件说明:如原理图所示, 103的PA10 PA11分别接CP2102usb转串口芯片的TXD RXD引脚.CP2102芯片是将串口和电脑USB接口进行了转接,方便应用灵活. 片上串口驱动代码如下. ...
- webpack4打包报错ERROR in multi ./src/main.js dist/bundle.js
webpack打包测试: 上边将mode01.js模块及main.js主文件编写完成,下边使用webpack对这些js文件进行打包 1.进入程序目录,执行webpack main.js build.j ...