【jvm】02-手写自己的类加载器

欢迎关注b站账号/公众号【六边形战士夏宁】,一个要把各项指标拉满的男人。该文章已在github目录收录。

屏幕前的大帅比大漂亮如果有帮助到你的话请顺手点个赞、加个收藏这对我真的很重要。别下次一定了,都不关注上哪下次一定。

1.简单手写自己的类加载器

创建一个类继承ClassLoader,然后重写findClass、loadClass这两个方法

findClass的方法

private static byte[] loadByte(String name) throws Exception {
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classPath + "/" + name
+ ".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
} protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadByte(name);
//defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
}

loadClass直接复制ClassLoader中的方法然后把错误的行数删除就行了

重点改动代码如下,让该自己的加载器加载指定包的文件,注意需要提前编译java文件为class

if (name.startsWith("com.example.demo.lesson")) {
c = findClass(name);
} else {
c = this.getParent().loadClass(name);
}

2.加载一个和jdk中同名的类

创建一个java.lang.Byte的类,然后用自己的类加载器去加载,然后就触发了jdk的沙箱机制,报了一个安全错误

tomcat的类加载器逻辑

如图所示,这里的核心其实就是每一个war包的代码即使含有同名的类也可以加载

做法如下,自己的classloader复制一份然后加载同一个class文件,可以看到启用的是不同的加载器,都被加载了

3.完整代码

package com.example.demo.lesson.jvm.myloader;

import java.io.FileInputStream;

/**
* @author seal email:876651109@qq.com
* @date 2020/9/1 7:23 PM
* @description
*/
public class MyClassLoaderDemo { public static void main(String[] args) throws ClassNotFoundException {
// Class clazz1 = new MyClassLoader().loadClass("com.example.demo.lesson.jvm.loader.A",false);
//Class clazz1 = new MyClassLoader().loadClass("java.lang.Byte",false);
Class clazz2 = new MyClassLoader2().loadClass("com.example.demo.lesson.jvm.loader.A",false);
System.out.println(new MyClassLoaderDemo().getClass().getClassLoader());
// System.out.println(clazz1.getClassLoader());
System.out.println(clazz2.getClassLoader());
} public static String classPath = "F:\\IdeaProjects\\TechingCode\\demoGrace\\src\\main\\java";
private static byte[] loadByte(String name) throws Exception {
name = name.replaceAll("\\.", "/");
FileInputStream fis = new FileInputStream(classPath + "/" + name
+ ".class");
int len = fis.available();
byte[] data = new byte[len];
fis.read(data);
fis.close();
return data;
} static class MyClassLoader extends ClassLoader { @Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadByte(name);
//defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
} @Override
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();
if (name.startsWith("java.lang.Byte")) {
c = findClass(name);
} else {
c = this.getParent().loadClass(name);
}
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
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
} static class MyClassLoader2 extends ClassLoader { @Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] data = loadByte(name);
//defineClass将一个字节数组转为Class对象,这个字节数组是class文件读取后最终的字节数组。
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
} @Override
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();
if (name.startsWith("com.example.demo.lesson")) {
c = findClass(name);
} else {
c = this.getParent().loadClass(name);
}
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
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
}
}

4.ConstantPool

Constant pool:
#1 = Methodref #2.#3 // java/lang/Object."<init>":()V
#2 = Class #4 // java/lang/Object
#3 = NameAndType #5:#6 // "<init>":()V
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Fieldref #8.#9 // com/example/demo/lesson/jvm/construction/Master.master2:Lcom/example/demo/lesson/jvm/construction/Master;
#8 = Class #10 // com/example/demo/lesson/jvm/construction/Master
#9 = NameAndType #11:#12 // master2:Lcom/example/demo/lesson/jvm/construction/Master;
#10 = Utf8 com/example/demo/lesson/jvm/construction/Master
#11 = Utf8 master2
#12 = Utf8 Lcom/example/demo/lesson/jvm/construction/Master;
#13 = Fieldref #8.#14 // com/example/demo/lesson/jvm/construction/Master.master4:Lcom/example/demo/lesson/jvm/construction/Master;
#14 = NameAndType #15:#12 // master4:Lcom/example/demo/lesson/jvm/construction/Master;
#15 = Utf8 master4
#16 = Fieldref #8.#17 // com/example/demo/lesson/jvm/construction/Master.int2:I
#17 = NameAndType #18:#19 // int2:I
#18 = Utf8 int2
#19 = Utf8 I
#20 = Fieldref #8.#21 // com/example/demo/lesson/jvm/construction/Master.int4:I
#21 = NameAndType #22:#19 // int4:I
#22 = Utf8 int4
#23 = Methodref #24.#25 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
#24 = Class #26 // java/lang/Integer
#25 = NameAndType #27:#28 // valueOf:(I)Ljava/lang/Integer;
#26 = Utf8 java/lang/Integer
#27 = Utf8 valueOf
#28 = Utf8 (I)Ljava/lang/Integer;
#29 = Fieldref #8.#30 // com/example/demo/lesson/jvm/construction/Master.integerMax2:Ljava/lang/Integer;
#30 = NameAndType #31:#32 // integerMax2:Ljava/lang/Integer;
#31 = Utf8 integerMax2
#32 = Utf8 Ljava/lang/Integer;
#33 = Fieldref #8.#34 // com/example/demo/lesson/jvm/construction/Master.integerMax4:Ljava/lang/Integer;
#34 = NameAndType #35:#32 // integerMax4:Ljava/lang/Integer;
#35 = Utf8 integerMax4
#36 = Fieldref #8.#37 // com/example/demo/lesson/jvm/construction/Master.integerMin2:Ljava/lang/Integer;
#37 = NameAndType #38:#32 // integerMin2:Ljava/lang/Integer;
#38 = Utf8 integerMin2
#39 = Fieldref #8.#40 // com/example/demo/lesson/jvm/construction/Master.integerMin4:Ljava/lang/Integer;
#40 = NameAndType #41:#32 // integerMin4:Ljava/lang/Integer;
#41 = Utf8 integerMin4
#42 = String #43 // str25
#43 = Utf8 str25
#44 = Fieldref #8.#45 // com/example/demo/lesson/jvm/construction/Master.str2:Ljava/lang/String;
#45 = NameAndType #46:#47 // str2:Ljava/lang/String;
#46 = Utf8 str2
#47 = Utf8 Ljava/lang/String;
#48 = String #49 // str27
#49 = Utf8 str27
#50 = Fieldref #8.#51 // com/example/demo/lesson/jvm/construction/Master.str4:Ljava/lang/String;
#51 = NameAndType #52:#47 // str4:Ljava/lang/String;
#52 = Utf8 str4
#53 = Class #54 // java/lang/String
#54 = Utf8 java/lang/String
#55 = String #56 // str30
#56 = Utf8 str30
#57 = Methodref #53.#58 // java/lang/String."<init>":(Ljava/lang/String;)V
#58 = NameAndType #5:#59 // "<init>":(Ljava/lang/String;)V
#59 = Utf8 (Ljava/lang/String;)V
#60 = Fieldref #8.#61 // com/example/demo/lesson/jvm/construction/Master.strN2:Ljava/lang/String;
#61 = NameAndType #62:#47 // strN2:Ljava/lang/String;
#62 = Utf8 strN2
#63 = String #64 // str32
#64 = Utf8 str32
#65 = Fieldref #8.#66 // com/example/demo/lesson/jvm/construction/Master.strN4:Ljava/lang/String;
#66 = NameAndType #67:#47 // strN4:Ljava/lang/String;
#67 = Utf8 strN4
#68 = String #69 // str35
#69 = Utf8 str35
#70 = Methodref #53.#71 // java/lang/String.intern:()Ljava/lang/String;
#71 = NameAndType #72:#73 // intern:()Ljava/lang/String;
#72 = Utf8 intern
#73 = Utf8 ()Ljava/lang/String;
#74 = Fieldref #8.#75 // com/example/demo/lesson/jvm/construction/Master.strI2:Ljava/lang/String;
#75 = NameAndType #76:#47 // strI2:Ljava/lang/String;
#76 = Utf8 strI2
#77 = String #78 // str37
#78 = Utf8 str37
#79 = Fieldref #8.#80 // com/example/demo/lesson/jvm/construction/Master.strI4:Ljava/lang/String;
#80 = NameAndType #81:#47 // strI4:Ljava/lang/String;
#81 = Utf8 strI4
#82 = String #83 // str54
#83 = Utf8 str54
#84 = String #85 // str56
#85 = Utf8 str56
#86 = String #87 // str57
#87 = Utf8 str57
#88 = String #89 // str59
#89 = Utf8 str59
#90 = String #91 // str60
#91 = Utf8 str60
#92 = Fieldref #93.#94 // java/lang/System.out:Ljava/io/PrintStream;
#93 = Class #95 // java/lang/System
#94 = NameAndType #96:#97 // out:Ljava/io/PrintStream;
#95 = Utf8 java/lang/System
#96 = Utf8 out
#97 = Utf8 Ljava/io/PrintStream;
#98 = Fieldref #8.#99 // com/example/demo/lesson/jvm/construction/Master.integerMin1:Ljava/lang/Integer;
#99 = NameAndType #100:#32 // integerMin1:Ljava/lang/Integer;
#100 = Utf8 integerMin1
#101 = Methodref #102.#103 // java/io/PrintStream.println:(Z)V
#102 = Class #104 // java/io/PrintStream
#103 = NameAndType #105:#106 // println:(Z)V
#104 = Utf8 java/io/PrintStream
#105 = Utf8 println
#106 = Utf8 (Z)V
#107 = Fieldref #8.#108 // com/example/demo/lesson/jvm/construction/Master.integerMax1:Ljava/lang/Integer;
#108 = NameAndType #109:#32 // integerMax1:Ljava/lang/Integer;
#109 = Utf8 integerMax1
#110 = Fieldref #8.#111 // com/example/demo/lesson/jvm/construction/Master.strN1:Ljava/lang/String;
#111 = NameAndType #112:#47 // strN1:Ljava/lang/String;
#112 = Utf8 strN1
#113 = String #114 // str29
#114 = Utf8 str29
#115 = String #116 // abc
#116 = Utf8 abc
#117 = Fieldref #8.#118 // com/example/demo/lesson/jvm/construction/Master.master1:Lcom/example/demo/lesson/jvm/construction/Master;
#118 = NameAndType #119:#12 // master1:Lcom/example/demo/lesson/jvm/construction/Master;
#119 = Utf8 master1
#120 = Fieldref #8.#121 // com/example/demo/lesson/jvm/construction/Master.master3:Lcom/example/demo/lesson/jvm/construction/Master;
#121 = NameAndType #122:#12 // master3:Lcom/example/demo/lesson/jvm/construction/Master;
#122 = Utf8 master3
#123 = Fieldref #8.#124 // com/example/demo/lesson/jvm/construction/Master.int3:I
#124 = NameAndType #125:#19 // int3:I
#125 = Utf8 int3
#126 = Fieldref #8.#127 // com/example/demo/lesson/jvm/construction/Master.integerMax3:Ljava/lang/Integer;
#127 = NameAndType #128:#32 // integerMax3:Ljava/lang/Integer;
#128 = Utf8 integerMax3
#129 = Fieldref #8.#130 // com/example/demo/lesson/jvm/construction/Master.integerMin3:Ljava/lang/Integer;
#130 = NameAndType #131:#32 // integerMin3:Ljava/lang/Integer;
#131 = Utf8 integerMin3
#132 = String #133 // str26
#133 = Utf8 str26
#134 = Fieldref #8.#135 // com/example/demo/lesson/jvm/construction/Master.str3:Ljava/lang/String;
#135 = NameAndType #136:#47 // str3:Ljava/lang/String;
#136 = Utf8 str3
#137 = String #138 // str31
#138 = Utf8 str31
#139 = Fieldref #8.#140 // com/example/demo/lesson/jvm/construction/Master.strN3:Ljava/lang/String;
#140 = NameAndType #141:#47 // strN3:Ljava/lang/String;
#141 = Utf8 strN3
#142 = String #143 // str34
#143 = Utf8 str34
#144 = Fieldref #8.#145 // com/example/demo/lesson/jvm/construction/Master.strI1:Ljava/lang/String;
#145 = NameAndType #146:#47 // strI1:Ljava/lang/String;
#146 = Utf8 strI1
#147 = String #148 // str36
#148 = Utf8 str36
#149 = Fieldref #8.#150 // com/example/demo/lesson/jvm/construction/Master.strI3:Ljava/lang/String;
#150 = NameAndType #151:#47 // strI3:Ljava/lang/String;
#151 = Utf8 strI3
#152 = Utf8 int1
#153 = Utf8 ConstantValue
#154 = Integer 9
#155 = Integer 10
#156 = Utf8 str1
#157 = String #158 // str24
#158 = Utf8 str24
#159 = Utf8 Code
#160 = Utf8 LineNumberTable
#161 = Utf8 main
#162 = Utf8 ([Ljava/lang/String;)V
#163 = Utf8 StackMapTable
#164 = Class #165 // "[Ljava/lang/String;"
#165 = Utf8 [Ljava/lang/String;
#166 = Utf8 <clinit>
#167 = Utf8 SourceFile
#168 = Utf8 Master.java

参考资料

《深入理解Java虚拟机》-周志明

【jvm】02-手写自己的类加载器的更多相关文章

  1. JVM 类的生命周期、类加载器

    类的加载.连接与初始化                  • 1. 加载:查找并加载类的二进制数据         • 2. 连接             – 2.1 验证:确保被加载的类的正确性   ...

  2. 【JVM】查看JVM加载的类及类加载器的方法

    查看JVM加载了哪些类 java -verbose[:class|gc|jni] 在输出设备上显示虚拟机运行信息. java -verbose:class 在程序运行的时候有多少类被加载!你可以用ve ...

  3. JVM知识(二):类加载器原理

    我们知道我们编写的java代码,会经过编译器编译成字节码(class文件),再把字节码文件装载到JVM中,最后映射到各个内存区域中,我们的程序就可以在内存中运行了.那么问题来了,这些字节码文件是怎么装 ...

  4. 深入了解java虚拟机(JVM) 第十二章 类加载器

    一.什么是类加载器 类加载器是一个用来加载类文件的类,Java源代码通过javac编译器编译成类文件,然后JVM来执行类文件中的字节码来执行程序.需要注意的是,只有被同一个类加载器加载的类才可能会相等 ...

  5. 【JVM学习笔记】线程上下文类加载器

    有许多地方能够看到线程上下文类加载的设置,比如在sun.misc.Launcher类的构造方法中,能够看到如下代码 先写一个例子建立感性认识 public class Test { public st ...

  6. 写一个自定义类加载器demo

    public class MyTest16 extends ClassLoader { private String classLoaderName; private String fileExten ...

  7. JVM源码分析之自定义类加载器如何拉长YGC

    概述 本文重点讲述毕玄大师在其公众号上发的一个GC问题一个jstack/jmap等不能用的case,对于毕大师那篇文章,题目上没有提到GC的那个问题,不过进入到文章里可以看到,既然文章提到了jstac ...

  8. 深入JVM系列(三)之类加载、类加载器、双亲委派机制与常见问题

    一.概述   定义:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型.类加载和连接的过程都是在运行期间完成的. 二. 类的 ...

  9. 【JVM第二篇--类加载机制】类加载器与双亲委派模型

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.什么是类加载器 在类加载过程中,加载阶段有一个动作是"通过一个类的全限 ...

随机推荐

  1. GO 总章

    GO 学习资源 go 代理 GO 语言结构 GO 数字运算 GO 时间处理 GO 定时器 GO 异常处理 go recover让崩溃的程序继续执行 GO Exit Fatal panic GO 通过进 ...

  2. android:textAppearance解析

    Android的系统自带的文字外观设置及实际显示效果图 android:textAppearancexml布局里面设置文字的外观: 如"android:textAppearance=&quo ...

  3. CentOS6设置Django开发环境

    今天在我的Centos6.5机器上安装 Django 开发环境,在安装完使用 "django-admin.py startproject myapp" 创建应用的时候报了下面的错误 ...

  4. Spring(4):Mybatis和Spring整合

    第一步:创建数据库 MySQL代码 1 CREATE DATABASE `mybatis` ; 2 3 USE `mybatis`; 4 5 CREATE TABLE `user` ( 6 `id` ...

  5. Servlet(1):Servlet介绍

    一. Servlet介绍 Servlet 是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生 ...

  6. MyBatis(3):优化MyBatis配置文件

    一.连接数据库的配置单独放在一个properties文件中 1,创建一个database.properties driver=com.mysql.jdbc.Driver url=jdbc:mysql: ...

  7. Redis缓存穿透、缓存击穿以及缓存雪崩

    作为一个内存数据库,redis也总是免不了有各种各样的问题,这篇文章主要是针对其中三个问题进行讲解:缓存穿透.缓存击穿和缓存雪崩.并给出一些解决方案.这三个问题是基本问题也是面试常问问题. 这篇文章我 ...

  8. 【C/C++】函数的分文件编写

    创建同名的头文件(.h)和cpp文件. 在头文件里写函数声明,在cpp文件中写函数定义. 在cpp文件中写#include "xx.h" //自定义头文件名 框架(include ...

  9. 剖析虚幻渲染体系(13)- RHI补充篇:现代图形API之奥义与指南

    目录 13.1 本篇概述 13.1.1 本篇内容 13.1.2 概念总览 13.1.3 现代图形API特点 13.2 设备上下文 13.2.1 启动流程 13.2.2 Device 13.2.3 Sw ...

  10. 利用Windbg分析Magicodes.IE一次错误编写导致内存剧增

    由于这近一年时间一直忙于写书和工作,一直没有水文,但是近期有几位朋友使用我们的Magicodes.IE反馈在导出过程中内存暴涨...好吧,不管怎样,不能苦了我们朋友,接下来我们通过windbg来看一下 ...