一、sun.misc.Launcher (ExtClassLoader 与 AppClassLoader 的创建)

public Launcher() {
Launcher.ExtClassLoader var1;
try {
var1 = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
} try {
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
} Thread.currentThread().setContextClassLoader(this.loader);
String var2 = System.getProperty("java.security.manager");
if (var2 != null) {
SecurityManager var3 = null;
if (!"".equals(var2) && !"default".equals(var2)) {
try {
var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
} catch (IllegalAccessException var5) {
} catch (InstantiationException var6) {
} catch (ClassNotFoundException var7) {
} catch (ClassCastException var8) {
}
} else {
var3 = new SecurityManager();
} if (var3 == null) {
throw new InternalError("Could not create SecurityManager: " + var2);
}
System.setSecurityManager(var3);
}
}

二、自定义类加载器(继承 ClassLoader 类,重写 findClass 方法,不推荐重写 loadClass 方法,会破坏委派机制)

测试加载类,使用 javac 把 .java 文件编译成 .class 文件

package com;

public class Hello {
static {
System.out.println("Hello !");
} public void sayHi(String name){
System.out.println("Hello !" + name);
}
}

类加载器,注意要加载类的路径名与包名

package com;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method; public class ClassLoaderTest extends ClassLoader { private final static String filePathSuffix = ".class";
private String filePathPrefix; public ClassLoaderTest(String filePathPrefix) {
this.filePathPrefix = filePathPrefix;
} @Override
protected Class<?> findClass(String name) {
String fileName = name.split("\\.")[name.split("\\.").length - 1];
byte[] bytes = loadClassData(filePathPrefix + fileName + filePathSuffix);
return defineClass(name, bytes, 0, bytes.length);
} private byte[] loadClassData(String filePath) {
InputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(new File(filePath));
out = new ByteArrayOutputStream();
int i = 0;
while ((i = in.read()) != -1) {
out.write(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return out.toByteArray();
} public static void main(String[] args) throws Exception {
ClassLoaderTest clt = new ClassLoaderTest("D:/");
Class c = clt.loadClass("com.Hello");
System.out.println(c.getClassLoader());
System.out.println(c.getClassLoader().getParent());
System.out.println(c.getClassLoader().getParent().getParent());
System.out.println(c.getClassLoader().getParent().getParent().getParent());
Method sayHi = c.getMethod("sayHi", String.class);
// 无参实例化
Object o = c.newInstance();
// 调用方法
sayHi.invoke(o, "zhangsan");
}
}

三、Class.forName() 和 ClassLoader.loadClass()

调用了 forName0,第二个参数为 true,默认会初始化,可使用其重载方法指定为 false

@CallerSensitive
public static Class<?> forName(String className) throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

调用了 loadClass 的重载方法,默认不会链接,就不会初始化了

public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}

以上面的 Hello 类为例,在 com 包下新建同样的文件,命名为 Hello1

public static void main(String[] args) throws Exception {
// 加载,链接,初始化
Class.forName("com.Hello1");
System.out.println("==========================================");
// 加载,链接
Class.forName("com.Hello1", false,ClassLoader.getSystemClassLoader());
System.out.println("==========================================");
// 加载
ClassLoader.getSystemClassLoader().loadClass("com.Hello1");
}

四、线程上下文类加载器(ThreadContextClassLoader)

https://mp.weixin.qq.com/s/4FJbRLUcg8FmOqP1uz3f2A

java.lang.Thread 中的方法 getContextClassLoader() 和 setContextClassLoader(ClassLoader cl) 用来获取和设置线程的上下文类加载器。

如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。

Java 应用运行的初始线程的上下文类加载器是系统类加载器。

Thread thread = new Thread(()->{
try {
Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass("com.Hello");
System.out.println(aClass.getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
});
thread.setContextClassLoader(new ClassLoaderTest("D:/"));
thread.start(); Thread.sleep(1000); thread = new Thread(()->{
try {
Class<?> aClass = Thread.currentThread().getContextClassLoader().loadClass("com.Hello1");
System.out.println(aClass.getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
});
thread.start();


https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.3.2

https://www.cnblogs.com/editice/p/5420712.html

Java-JVM 自定义类加载器的更多相关文章

  1. JVM自定义类加载器加载指定classPath下的所有class及jar

    一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...

  2. (转)JVM——自定义类加载器

    背景:为什么要自定义,如何自定义,实现过程 转载:http://blog.csdn.net/SEU_Calvin/article/details/52315125 0. 为什么需要自定义类加载器 网上 ...

  3. JVM——自定义类加载器

    )以上两种情况在实际中的综合运用:比如你的应用需要通过网络来传输 Java 类的字节码,为了安全性,这些字节码经过了加密处理.这个时候你就需要自定义类加载器来从某个网络地址上读取加密后的字节代码,接着 ...

  4. JVM 自定义类加载器在复杂类情况下的运行分析

    一.自定义类加载器在复杂类情况下的运行分析 1.使用之前创建的类加载器 public class MyTest16 extends ClassLoader{ private String classN ...

  5. JVM 自定义类加载器

    一.创建自定义类加载器 package com.example.jvm.classloader; import java.io.ByteArrayOutputStream; import java.i ...

  6. Java JVM——2.类加载器子系统

    概述 类加载器子系统在Java JVM中的位置 类加载器子系统的具体实现 类加载器子系统的作用 ① 负责从文件系统或者网络中加载.class文件,Class 文件在文件开头有特定的文件标识. ② Cl ...

  7. Java使用自定义类加载器实现热部署

    热部署: 热部署就是在不重启应用的情况下,当类的定义即字节码文件修改后,能够替换该Class创建的对象.一般情况下,类的加载都是由系统自带的类加载器完成,且对于同一个全限定名的java类,只能被加载一 ...

  8. java jvm虚拟机类加载器

    在Java中任意一个类都是由这个类本身和加载这个类的类加载器来确定这个类在JVM中的唯一性. 类加载器 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到J ...

  9. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  10. java自定义类加载器

    前言 java反射,最常用的Class.forName()方法.做毕设的时候,接收到代码字符串,通过 JavaCompiler将代码字符串生成A.class文件(存放在classpath下,也就是ec ...

随机推荐

  1. Golang Gateway API 搭建教程

    原文链接 随着微服务的兴起,行业里出现了非常多优秀的微服务网关框架,今天教大家搭建一套国人,用Golang写的微服务网关框架. 这里啰嗦一句,可能到今天还有人不理解什么是微服务,为什么要用微服务.目前 ...

  2. hbuilder打包集成文件预览

    <div class="attachments"> <div class="name">附件</div> <div c ...

  3. 第十五章、Python多线程同步锁,死锁和递归锁

    目录 第十五章.Python多线程同步锁,死锁和递归锁 1. 引子: 2.同步锁 3.死锁 引子: 4.递归锁RLock 原理: 不多说,放代码 总结: 5. 大总结 第十五章.Python多线程同步 ...

  4. GMT、UTC、UNIX时间戳、时区

    GMT.UTC.CTS: UTC时间:世界协调时间(UTC)是世界上不同国家用来调节时钟和时间的主要时间标准,也就是零时区的时间.UTC是以原子时秒长为基础,在时刻上尽量接近于GMT的一种时间计量系统 ...

  5. BLE 5协议栈-直接测试模式

    文章转载自:http://www.sunyouqun.com/2017/04/page/3/ BLE协议充分考虑了设备的测试问题,在协议栈层面提供了直接测试模式,用于执行BLE设备的RF物理层一致性的 ...

  6. 【网络协议】ARP地址解析协议

    地址解析协议ARP 在以太网协议中规定,同一局域网中的一台主机要和另一台主机进行直接通信,必须要知道目标主机的MAC地址.而在TCP/IP协议中,网络层和传输层只关心目标主机的IP地址.这就导致在以太 ...

  7. sql 183. 从不订购的客户

    SQL架构 某网站包含两个表,Customers 表和 Orders 表.编写一个 SQL 查询,找出所有从不订购任何东西的客户. Customers 表: +----+-------+ | Id | ...

  8. bind的各种辅助工具

    dig dig用于测试dns系统,因此,不会查询hosts文件进行解析.

  9. maven项目pom.xml中parent标签的使用(转)

    原文地址:https://blog.csdn.net/qq_41254677/article/details/81011681 使用maven是为了更好的帮项目管理包依赖,maven的核心就是pom. ...

  10. 33. ClustrixDB 扩展集群的容量-Flex up

    ClustrixDB被授权为每个节点的最大核数以及集群的最大节点数.如果需要扩展许可证,请联系Clustrix Sales.扩容之前检查License是否支持节点数. 一.准备节点 提供节点并在每个节 ...