核心思路是确保关键类由高优先级类加载器加载且不可被替换:通过双亲委派机制,利用-Xbootclasspath/a或-Djava.ext.dirs将核心类交由Bootstrap/Extension ClassLoader加载;自研FrameworkClassLoader在loadClass入口强制委派并拦截非法defineClass;构建期用Maven/Gradle插件、注解处理器和打包脚本静态拦截;运行时校验所有核心类加载器必须为ExtClassLoader或BootstrapClassLoader,否则启动失败。

核心思路不是“不让别人写类”,而是让关键类根本无法被替换——无论开发人员怎么定义,JVM 都只会加载框架预置的那一份。
强制由高优先级类加载器接管核心类
Java 类加载的双亲委派机制天然支持这种控制:只要确保 java.*、javax.*、com.myframe.* 等关键包下的类,始终由 Bootstrap 或 Extension ClassLoader 加载,Application ClassLoader 就永远没机会加载同名类。
- 启动时通过
-Xbootclasspath/a:myframe-core.jar将框架核心 JAR 追加进 Bootstrap 加载范围(适用于极少数不可妥协的核心类,如com.myframe.kernel.Kernel) - 或使用
-Djava.ext.dirs=/opt/myframe/ext:$JAVA_HOME/jre/lib/ext,把框架核心库放入扩展路径,交由 Extension ClassLoader 加载 - 此时即使开发人员在
src/main/java下写了com.myframe.core.ConfigManager,JVM 在loadClass("com.myframe.core.ConfigManager")时也会直接返回 Extension 加载的版本,完全跳过应用类路径扫描
自研类加载器做运行时拦截
仅靠 JVM 默认委派不够严谨,需在框架层加固。自研 FrameworkClassLoader 应继承 ClassLoader,重写 loadClass 方法,在委托前主动干预:
- 对包名匹配
java.、javax.、com.myframe.的类,强制调用getSystemClassLoader().getParent().loadClass(...),即跳过自身查找,直连 Extension - 若检测到
defineClass尝试定义上述包下的类,立即抛出SecurityException并记录审计日志 - 不覆盖
findClass,保留标准委派骨架,只在入口处插入白名单校验逻辑
编译期与构建期提前阻断
等代码跑起来再拦截,风险已发生。必须把防线前移至源码和构建阶段:
立即学习“Java免费学习笔记(深入)”;
- Maven/Gradle 插件集成静态扫描:发现
java.lang.String、com.myframe.security.Authenticator等敏感包下声明了 public class,构建直接失败 - 定义
@RestrictedPackage注解,配合注解处理器,在 IDE 编辑时就标红提示“禁止在此包下定义类” - 打包脚本检查
BOOT-INF/classes/目录,若存在与核心包冲突的 class 文件,拒绝生成可部署包
运行时唯一性断言兜底
JVM 规定:同一个全限定类名 + 不同类加载器 = 两个不同类。框架初始化时可做一致性校验:
- 遍历所有已加载类,筛选出
com.myframe.core.*包下的类 - 断言它们的
getClassLoader()必须是ExtClassLoader或BootstrapClassLoader - 一旦发现某核心类由
AppClassLoader加载,立即中止启动并报致命错误


















