流量时代的狂欢:揭秘“中国美女”视频背后的真相与人性博弈
内容来自JVMS Chapter 5 – Loading, Linking, and Initialization类加载、链接、初始化这是 JVM 规范中对类加载的正式描述。
这不是教材版而是接近 JVM 规范原文的专业
总结版。
JVM 不定义类加载器的层次结构、不强制双亲委派也不定义 classpath。
它只要求类必须通过某个加载器被定义类的身份由“类名 加载器”唯一确定。
加载、链接、初始化的每个环节必须按规范精确执行。
JVM 规范中类加载属于更大的过程Loading → Linking → Initialization加载 → 链接 → 初始化JVMS 定义类处理流程分为三大阶段
Loading加载
Linking链接
1 Verification验证
2 Preparation准备
3 Resolution解析
Initialization初始化类加载只是整个过程的第一步不包含解析、初始化。
JVM 如何定义 “类加载Loading”JVMS 定义Class loading is the process of locating a binary representation of a class or interface and transforming it into the runtime data structure inside the JVM.类加载 找到类的二进制表示并创建其在 JVM 中的运行时表示。
规范强调三点1“二进制表示”不限于 .class 文件可以来自.class/JAR/网络/动态生成的字节数组如 ASM/CGLIB/数据库/加密文件JVM 标准不限制来源。
2类加载器负责找到这个“二进制表示”规范中称之为defineClass findClass3加载结果是method area或 Metaspace中的 Class 对象规范描述为runtime representation of classes 类的运行时表示
JVM 规范如何描述类加载器ClassLoader类加载器不是 Java 语言的组成部分但 JVM 规范要求The Java Virtual Machine must maintain a mapping between class loaders and the classes they have loaded.Java虚拟机必须维护类加载器与其加载的类之间的映射关系。
这意味着每个类都有一个加载器标识类的身份 (className classLoader)类的身份 (className classLoader)
JVM 标准如何描述 “类加载器之间的关系”最关键的一段The Java Virtual Machine specification does not require class loaders to follow a parent-child hierarchy.Java虚拟机规范不要求类加载器遵循父子层次结构。
也就是说双亲委派不是 JVM 强制的是 Java ClassLoader 的一种“设计模式”而不是 JVM 的硬规则JVM 层面只关心“由哪个加载器加载”
JVM 规范如何要求加载器委派parent delegation非常重要的一段The delegation model is strongly recommended but not strictly required by this specification.本规范强烈建议采用委托模型但并非严格要求。
这意味着HotSpot 的默认加载器链Bootstrap → Ext/Platform → App是Launcher(JDK
/ClassLoaders(JDK
Java 层设计的不是 JVM 强制的容器Tomcat/OSGi可以合法地破坏它符合规范
JVM 规范如何描述类的唯一性Class Identity规范定义类的唯一标识为Class Identity (class name defining class loader)因此同名类由两个不同 ClassLoader 加载 → 两个不同的类注意这里两个不同的ClassLoader可以是不同类型的ClassLoader也可以是同类型ClassLoader的不同实例不同类型的ClassLoader// 类型1JDK 自带的 URLClassLoaderURL url classPath.toUri().toURL();URLClassLoader urlLoader new URLClassLoader(new URL[]{url}, null);// 类型2我们自己写的 MyFileClassLoader完全不同类型MyFileClassLoader myLoader new MyFileClassLoader(classPath, null);// 加载同一个类Class? c1 urlLoader.loadClass(a
Person);Class? c2 myLoader.loadClass(a
Person);不同实例// 两个完全一样的 class 文件但路径不同 → 两个不同的 ClassLoaderURL url1 Paths.get(D:/MyWork/0-create/practice idea/jvm/jvm-practice/out/production/part4/).toUri().toURL();URL url2 Paths.get(D:/MyWork/0-create/practice idea/jvm/jvm-practice/out/production/part4/).toUri().toURL();// 父加载器都设为 null直属 Bootstrap这样更纯粹也可以设为 getSystemClassLoader()URLClassLoader loader1 new URLClassLoader(new URL[]{url1}, null);URLClassLoader loader2 new URLClassLoader(new URL[]{url2}, null);// 加载同一个全限定名的类Class? clazz1 loader
loadClass(a
v
User);Class? clazz2 loader
loadClass(a
v
User);不能相互赋值、不能 instanceof、不能强制转型这是 OSGi、Tomcat 多版本隔离的理论基础。
JVM 如何描述“类加载触发条件”规范要求类只有在首次主动使用时才必须加载主动使用包括new 对象调用静态方法访问静态字段非 final反射 Class.forName引用 Class.forName初始化子类会触发父类加载JVM 启动加载 main 类
JVM 对生命周期的强制要求重要JVM 必须保证类必须按需加载lazy loading类只能被加载一次每个 ClassLoader 内同一加载器加载同名类必须返回同一 Class 对象加载器之间不能冲突父和子加载器加载同名类时是两个类
JVM 规范对 defineClass 的要求非常核心规范要求 defineClass 只做校验二进制格式将其转换为内部运行时结构绑定到当前 ClassLoader 的命名空间它不负责查找 class处理委派管理 classpath管理类路径这些都是 Java 层的 ClassLoader 负责的。
JVM 规范明确双亲委派不是必须 | 自定义加载器合法自定义 ClassLoader从 JVM 标准的角度完全合法只要保证defineClass 的字节码合法链接验证成功不替换 java.* 核心类否则安全管理器会禁止不与系统类冲突除非故意隔离下面是一个打破双亲委派的例子基于jdk17import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; public class MyClassLoaderJdk17 extends ClassLoader { private final String classPath; private final String targetPackagePrefix com.test; public MyClassLoaderJdk17(String classPath) { super(MyClassLoaderJdk
class.getClassLoader()); // parent app loader this.classPath classPath; } Override public Class? loadClass(String name) throws ClassNotFoundException { // JPMS 下绝不能尝试加载 java.*否则报错 if (name.startsWith(java.) || name.startsWith(jdk.) || name.startsWith(javax.)) { return super.loadClass(name); } // 对业务包破坏双亲委派 if (name.startsWith(targetPackagePrefix)) { synchronized (getClassLoadingLock(name)) { Class? loaded findLoadedClass(name); if (loaded ! null) return loaded; try { return findClass(name); } catch (Exception ignored) { } } } // 其余保持默认委派 return super.loadClass(name); } Override protected Class? findClass(String name) throws ClassNotFoundException { try { String file classPath / name.replace(., /) .class; byte[] bytes Files.readAllBytes(Paths.get(file)); return defineClass(name, bytes, 0, bytes.length); } catch (IOException e) { throw new ClassNotFoundException(name, e); } } }因此Tomcat 的 WebAppClassLoaderSPI 的 ThreadContextClassLoaderOSGi 的 BundleClassLoader完全符合 JVM 标准。
www.9696.gov.cnmpfgold.cn-www.9696.gov.cnmpfgold.cn最新版N.7.91.49-2285安卓网应用