探索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 ...
随机推荐
- Qt编写安防视频监控系统14-本地回放
一.前言 在上一篇文章将视频文件存储好了,需要提供界面方便用户查询视频文件进行回放,其实这个回放就是播放历史存储的视频文件,并不是什么高大上的东西,视频回放在这个系统中分三种,第一种是本地回放,回放存 ...
- 【翻译】Flink Table Api & SQL — SQL
本文翻译自官网:SQL https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/table/sql.html Flink Tab ...
- webpack打包完成,复制,打包,移动,删除已生成的文件插件
const FileManagerPlugin = require('filemanager-webpack-plugin'); 详情请到 https://www.npmjs.com/ 一看究竟 贴个 ...
- 最新 识装java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿. 识装等10家互联网公司的校招Offer,因为某些自身原因最终选择了 识装.6.7月主要是做系统复习.项目复盘.LeetCo ...
- 对get post等http请求方式的理解
本文是关于get,post等几种请求方式的资料搜集和学习,HTTP,HTTP2协议的涉及点,然后提到了socket协议,RPC 先是和朋友的一些交流对话,问着问着就到了我的知识盲区.需要恶补一下这方面 ...
- 修改mysql自增字段的方法
修改mysql自增字段的方法 修改 test_user 库 user 表 auto_increment为 10000(从10000开始递增) <pre>mysql> alter ta ...
- Mysql 学习整理
1 创建数据库 1.1数据库基本结构 数据库:数据库是表的集合,带有相关的数据. 表:一个表是多个字段的集合. 字段:一个字段是一列数据,由字段名和记录组成 1.2创建数据库 create datab ...
- pom.xml文件导入了坐标,也没有报错,为什么还是没有相关的jar包的?
为什么会出现这样的错误呢?仔细想了想,赶紧去本地仓库看看jar也没有导入进来 解决问题的思路,就是把假的jar包文件删除掉,然后在IDEA上的坐标复制删除粘贴,IDEA就会重新导入jar包,这时就成功 ...
- python3检测ossfs可用性+钉钉通知
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2019-12-02 15:16 # @Author : Anthony # @Emai ...
- 使用 Issue 管理软件项目详解
文章来源:http://www.ruanyifeng.com/blog/2017/08/issue.html 软件开发(尤其是商业软件)离不开项目管理,Issue 是最通用的管理工具之一. 本文介绍 ...