探索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 ...
随机推荐
- Java8 Stream流方法
流是Java API的新成员,它允许以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现).就现在来说,可以把它们看成遍历数据集的高级迭代器.此外,流还可以透明地并行处理,无需写任何多 ...
- 【转】SOA架构和微服务架构的区别
SOA架构和微服务架构的区别 https://blog.csdn.net/zpoison/article/details/80729052
- Linux开机报错,提示根目录有错误,无法通过检测进入系统
报错信息如下: VolGroup-lv_root contains a file system with errors, check forced. 修复方法:(因为我的是虚拟机,可以随意做备份,所以 ...
- [LeetCode] 276. Paint Fence 粉刷篱笆
There is a fence with n posts, each post can be painted with one of the k colors. You have to paint ...
- [LeetCode] 207. Course Schedule 课程安排
There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prer ...
- python jieba 词云
#!/usr/bin/python # coding:utf-8 # 绘制一个<三体>全集词云 # pip install jieba # pip install matplotlib # ...
- mysql查看和修改最大连接数
查看最大连接数 SHOW VARIABLES LIKE '%max_connections%'; 修改最大连接数 ;
- Module 'mysql' already loaded in Unknown on line 0解决方法
Module 'mysql' already loaded in Unknown on line 0解决方法 直接进入php.ini 把;extension=mysql.so注释掉就好了
- Mybatis获取数据库自增主键
一般我们都为将表中主键列设置为自增,当我们执行插入语句时,比如这样 //测试添加 Employee employee = new Employee(null, "jerry4",n ...
- 【面试】IP数据报格式分析
(除选项外的报头区总共20个字节) 1)版本:IPV4/IPV6 2)头长度:报头区长度,用于计算数据区的开始位置,比如头长度为6,代表报头区长度为6*4个字节,头长度的单位为4字节,所以报头区长度不 ...