探索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编写图片及视频TCP/UDP网络传输
一.前言 很多年前就做过类似的项目,无非就是将本地的图片上传到服务器,就这么简单,其实用http的post上传比较简单容易,无需自定义协议,直接设置好二进制数据即可,而采用TCP或者UDP通信的话,必 ...
- matlab学习笔记8 基本绘图命令-基本绘图操作
一起来学matlab-matlab学习笔记8 基本绘图命令_2基本绘图操作 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matlab 程序设计与综合应用>张德丰等著 ...
- git让线上代码强制覆盖本地的
git强制覆盖本地命令(分步执行): git fetch --all git reset --hard origin/master git pull git强制覆盖本地命令(单条执行): ...
- k8s添加凭证
请参照:https://www.cnblogs.com/effortsing/p/10013441.html
- [LeetCode] 504. Base 7 基数七
Given an integer, return its base 7 string representation. Example 1: Input: 100 Output: "202&q ...
- 机试指南第二章-经典入门-Hash的应用自解
Hash的应用: Hash即散列,不像数据结构与算法中讲的各种Hash方法和冲突处理等过多的阐述,以下主要介绍Hash在机试试题解答中的作用. 例2.5 统计同成绩学生人数 Hash解法AC代码:(一 ...
- 09 Spring的依赖注入
1.依赖注入(Dependency Injection) (1)IOC的作用: 降低程序间的耦合(依赖关系)(2)依赖关系的管理: 以后都交给spring来维护 在当前类需要用到其他类的对象,由spr ...
- jwt 0.9.0(二)jwt官网资料总结
1.JWT描述 Jwt token由Header.Payload.Signature三部分组成,这三部分之间以小数点”.”连接,JWT token长这样: eyJhbGciOiJIUzI1NiIsIn ...
- GOF 的23种JAVA常用设计模式总结 03 面向对象七大设计原则
在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据 7 条原则来开发程序,从而提高软件开发效率.节约软件开发成本和维护成本. 各位代码界的大佬们总结出的七 ...
- 记录Quarter的基本使用
原文:记录Quarter的基本使用 using Quartz; using Quartz.Impl; using Quartz.Impl.Matchers; using Quartz.Logging; ...