Java-JVM 自定义类加载器
一、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 自定义类加载器的更多相关文章
- JVM自定义类加载器加载指定classPath下的所有class及jar
一.JVM中的类加载器类型 从Java虚拟机的角度讲,只有两种不同的类加载器:启动类加载器和其他类加载器. 1.启动类加载器(Boostrap ClassLoader):这个是由c++实现的,主要负责 ...
- (转)JVM——自定义类加载器
背景:为什么要自定义,如何自定义,实现过程 转载:http://blog.csdn.net/SEU_Calvin/article/details/52315125 0. 为什么需要自定义类加载器 网上 ...
- JVM——自定义类加载器
)以上两种情况在实际中的综合运用:比如你的应用需要通过网络来传输 Java 类的字节码,为了安全性,这些字节码经过了加密处理.这个时候你就需要自定义类加载器来从某个网络地址上读取加密后的字节代码,接着 ...
- JVM 自定义类加载器在复杂类情况下的运行分析
一.自定义类加载器在复杂类情况下的运行分析 1.使用之前创建的类加载器 public class MyTest16 extends ClassLoader{ private String classN ...
- JVM 自定义类加载器
一.创建自定义类加载器 package com.example.jvm.classloader; import java.io.ByteArrayOutputStream; import java.i ...
- Java JVM——2.类加载器子系统
概述 类加载器子系统在Java JVM中的位置 类加载器子系统的具体实现 类加载器子系统的作用 ① 负责从文件系统或者网络中加载.class文件,Class 文件在文件开头有特定的文件标识. ② Cl ...
- Java使用自定义类加载器实现热部署
热部署: 热部署就是在不重启应用的情况下,当类的定义即字节码文件修改后,能够替换该Class创建的对象.一般情况下,类的加载都是由系统自带的类加载器完成,且对于同一个全限定名的java类,只能被加载一 ...
- java jvm虚拟机类加载器
在Java中任意一个类都是由这个类本身和加载这个类的类加载器来确定这个类在JVM中的唯一性. 类加载器 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到J ...
- Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论
Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...
- java自定义类加载器
前言 java反射,最常用的Class.forName()方法.做毕设的时候,接收到代码字符串,通过 JavaCompiler将代码字符串生成A.class文件(存放在classpath下,也就是ec ...
随机推荐
- Windows地址栏的妙用
主角: 它就是windows自带的一个小工具->地址栏,可以通过在任务栏右键选择工具栏-地址栏添加使用. 妙用: 一.打开文件 使用方法:D:\Temp(文件路径) 小提示:快速进入回收站:Re ...
- JavaMaven【一、概述&环境搭建】
课程概述 JavaMaven[一.概述&环境搭建] JavaMaven[二.目录结构&HelloMaven] JavaMaven[三.常用指令] JavaMaven[四.坐标& ...
- linux命令详解——top
简介 TOP是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系 ...
- odoo 关系字段(关联关系)
Many-to-one关联 publisher_id = fields.Many2one(comodel_name= 'res.partner', domain='',context={},ondel ...
- Python爬虫解析htm时lxml的HtmlElement对象获取和设置inner html方法
Python的lxml是一个相当强悍的解析html.XML的模块,最新版本支持的python版本从2.6到3.6,是写爬虫的必备利器.它基于C语言库libxml2 和 libxslt,进行了Pytho ...
- Java语言基础(9)
1 方法(二) 1) 不带参数没有返回值的方法: 案例:Demo1 public class Demo1 { static void show(){ System.out.println(" ...
- CF888G Xor-MST[最小生成树+01trie]
前注:关于这题,本人的解法暂时没有成功通过此题,原因是被卡常了.可能需要等待某种机缘来请人调试. 类似uoj的一道题(新年的繁荣),不过是一个有些简单的版本. 因为是完全图,有没有办法明显优化建边,所 ...
- MySQL Audit日志审计
一.简介 数据库审计能够实时记录网络上的数据库活动,对数据库操作进行细粒度审计的合规性管理,对数据库受到的风险行为进行告警,对攻击行为进行阻断,它通过对用户访问数据库行为的记录.分析和汇报,用来帮助用 ...
- 用 D3.js 画一个手机专利关系图, 看看苹果,三星,微软间的专利纠葛
前言 本文灵感来源于Mike Bostock 的一个 demo 页面 原 demo 基于 D3.js v3 开发, 笔者将其使用 D3.js v5 进行重写, 并改为使用 ES6 语法. 源码: gi ...
- ubuntu配置环境变量 sudo gedit /etc/profile
文件末尾加入下面 JAVA_HOME 是jdk主目录 export JAVA_HOME=/usr/jdkexport JRE_HOME=${JAVA_HOME}/jre export CLASSPA ...