java虚拟机:ClassLoader分析

2024-08-24 05:32

本文主要是介绍java虚拟机:ClassLoader分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

序言

最近看了看ClassLoader,网上的博客挺多的,大部分都是你抄我的,我抄你的。在他们的基础上,自己打算写一篇,自己对ClassLoader的分析,也就是对现有blog的总结吧。

ClassLoader初始化源码。

在openjdk中可以看到下面的代码。

public Launcher() {// Create the extension class loaderClassLoader extcl;try {extcl = ExtClassLoader.getExtClassLoader();} catch (IOException e) {throw new InternalError("Could not create extension class loader");}// Now create the class loader to use to launch the applicationtry {loader = AppClassLoader.getAppClassLoader(extcl);} catch (IOException e) {throw new InternalError("Could not create application class loader");}// Also set the context class loader for the primordial thread.Thread.currentThread().setContextClassLoader(loader);// Finally, install a security manager if requestedString s = System.getProperty("java.security.manager");if (s != null) {SecurityManager sm = null;if ("".equals(s) || "default".equals(s)) {sm = new java.lang.SecurityManager();} else {try {sm = (SecurityManager)loader.loadClass(s).newInstance();} catch (IllegalAccessException e) {} catch (InstantiationException e) {} catch (ClassNotFoundException e) {} catch (ClassCastException e) {}}if (sm != null) {System.setSecurityManager(sm);} else {throw new InternalError("Could not create SecurityManager: " + s);}}
}

可以看到在Launcher构造函数的执行过程如下:

  1. 通过ExtClassLoader.getExtClassLoader()创建了ExtClassLoader;

  2. 通过AppClassLoader.getAppClassLoader(ExtClassLoader)创建了AppClassLoader,并将ExtClassLoader设为AppClassLoader的parent
    ClassLoader;

  3. 通过Thread.currentThread().setContextClassLoader(loader)把AppClassLoader设为线程的上下文
    ClassLoader;

JDK默认ClassLoader:

在jdk中默认了3种的ClassLoader:BootStrapClassLoader、ExtensionClassLoader和AppClassLoader。

  1. BootStrapClassLoader:它是最顶层的类加载器,是由C++编写而成,
    已经内嵌到JVM中了。在JVM启动时会初始化该ClassLoader,它主要用来读取Java的
    核心类库JRE/lib/rt.jar中所有的class文件,这个jar文件中包含了java规范定义的所有接口及实现。
  2. ExtensionClassLoader:它是用来读取Java的一些扩展类库,如读取JRE/lib/ext/*.jar中的包等(这里要注意,有些版本的是没有ext这个目录的)。
  3. AppClassLoaderBootstrp
    loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为
    ExtClassLoader。AppClassLoader也是用Java写成的,它的实现类是
    sun.misc.Launcher$AppClassLoader,另外我们知道ClassLoader中有个getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要负责加载classpath所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。

ClassLoader源码阅读

##成员变量
private final ClassLoader 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 ConcurrentHashMap parallelLockMap;
当前ClassLoader在并发情况下,一个锁的的对象。 Maps class name to the corresponding lock object when the current class loader is parallel capable. Note: VM also uses this field to decide if the current class loader is parallel capable and the appropriate lock object for class loading.

private final Map package2cert;

每个包的证书,是个HashTable

private static final Certificate[] nocerts = new Certificate[0];

Shared among all packages with unsigned classes

private final Vector> classes = new Vector<>();
这个class loader加载的所有类,这些类是从开始被GC到gc结束 The classes loaded by this class loader. The only purpose of this table is to keep the classes from being GC’ed until the loader is GC’ed.

private final ProtectionDomain defaultDomain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), null, this, null);

貌似是读写的策略,The “default” domain. Set as the default ProtectionDomain on newly created classes.

private final Set domains;

The initiating protection domains for all classes loaded by this loader

构建函数

私有的构造函数

   private ClassLoader(Void unused, ClassLoader parent) {this.parent = parent;if (ParallelLoaders.isRegistered(this.getClass())) {parallelLockMap = new ConcurrentHashMap<>();package2certs = new ConcurrentHashMap<>();domains =Collections.synchronizedSet(new HashSet<ProtectionDomain>());assertionLock = new Object();} else {// no finer-grained lock; lock on the classloader instanceparallelLockMap = null;package2certs = new Hashtable<>();domains = new HashSet<>();assertionLock = this;}}

也就是分为当前的ClassLoader是否被加载2种情况:ParallelLoaders.isRegistered(this.getClass())来判断是否可以并行

保护性的构造函数

 protected ClassLoader(ClassLoader parent) {this(checkCreateClassLoader(), parent);}protected ClassLoader() {this(checkCreateClassLoader(), getSystemClassLoader());}

checkCreateClassLoader():是校验下创建ClassLoader的权限
parent:是创建ClassLoader的父节点
getSystemClassLoader():是获取系统的ClassLoader,作为当前节点的父节点
3. loadClass

resolve:在虚拟机中找到一个类二进制,再根据resolve参数判断Classloader用来链接一个类

  protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass<?> 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 statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}

先进行getClassLoadingLock(以后会详细分析),然后查找已加载的类,在从父类ClassLoader查找,最后查找Bootstrap的ClassLoader

resolveClass:链接指定的类。这个方法给Classloader用来链接一个类,如果这个类已经被链接过了,那么这个方法只做一个简单的返回。否则,这个类将被按照 Java™规范中的Execution描述进行链接

##参照:
http://www.hollischuang.com/archives/199

这篇关于java虚拟机:ClassLoader分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1101579

相关文章

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏

javacv依赖太大导致jar包也大的解决办法

《javacv依赖太大导致jar包也大的解决办法》随着项目的复杂度和依赖关系的增加,打包后的JAR包可能会变得很大,:本文主要介绍javacv依赖太大导致jar包也大的解决办法,文中通过代码介绍的... 目录前言1.检查依赖2.更改依赖3.检查副依赖总结 前言最近在写项目时,用到了Javacv里的获取视频

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC