核心内容摘要
OWASP Threat Dragon安全评估实战:保护你的系统免受潜在威胁
java -jar是 Java 中运行可执行 JAR 包Executable JAR的核心命令其底层依托 JVM 类加载机制、JAR 包规范和程序入口约定实现核心逻辑是「JVM 解析 JAR 包元数据→加载指定主类→执行入口方法」以下从核心前提、完整启动流程、关键细节、与普通启动的区别四方面彻底讲清原理附实操验证和
注意事项。
核心前提可执行 JAR 包的特殊要求java -jar能启动的前提是JAR 包必须是「可执行 JAR」普通依赖 JAR 包仅含 class 文件无启动配置无法通过该命令运行。
可执行 JAR 包的核心标识是在META-INF/MANIFEST.MF文件中声明主类入口这是 JVM 识别「启动类」的唯一依据。
可执行 JAR 包的MANIFEST.MF核心配置该文件是 JAR 包的「元数据清单」java -jar启动时会优先读取其中的Main-Class属性格式要求严格冒号后必须有 1 个空格结尾无多余空行示例manifestManifest-Version:
0 Main-Class: com.example.DemoApplication # 核心指定程序入口主类含全类名 Class-Path: lib/commons-lang3-
3.
14.
jar lib/fastjson2-
2.
0.
jar # 可选依赖的外部JAR包路径Main-Class必填指定包含public static void main(String[] args)方法的主类全类名无.class后缀Class-Path可选声明当前 JAR 包依赖的外部 JAR 包相对路径多个依赖用空格分隔JVM 会按此加载依赖类格式要求属性名大小写固定冒号:后必须跟1 个空格否则 JVM 会解析失败。
普通 JAR 与可执行 JAR 的核心区别类型核心特征启动方式普通依赖 JAR仅含 class 文件无Main-Class无法java -jar仅作为其他项目的依赖被类加载可执行 JAR含Main-Class声明有主入口直接java -jar xxx.jar启动
java -jar xxx.jar完整启动流程JVM 视角当在命令行执行java -jar命令时JVM 会按固定步骤完成从「解析 JAR 包」到「执行 main 方法」的全过程无额外手动干预全程自动化步骤如下按执行顺序步骤 1JVM 解析命令行参数识别-jar标识JVM 启动器java.exe/java可执行文件首先解析命令行参数当检测到-jar标识时会触发 **「JAR 包启动模式」**后续逻辑均围绕「加载并运行可执行 JAR 包」展开同时忽略命令行中后续的其他类名参数仅以 JAR 包为核心。
步骤 2加载并解析 JAR 包中的META-INF/MANIFEST.MF文件JVM 会打开指定的 JAR 包如xxx.jar按规范读取其中META-INF目录下的MANIFEST.MF元数据文件核心做 2 件事校验文件格式是否合法如是否有Manifest-Version基础属性提取 **Main-Class属性值 **主类全类名若未找到该属性直接抛出异常no main manifest attribute, in xxx.jar最常见启动失败原因。
步骤 3基于 JAR 包创建专属的「JAR 类加载器JarClassLoader」Java 类加载遵循「双亲委派模型」但java -jar启动时JVM 会创建专属的 JarClassLoader继承自 URLClassLoader该类加载器的核心作用是以整个 JAR 包为「类加载源」负责从 JAR 包的压缩结构中加载所有 class 文件包括主类、业务类、内部依赖类若MANIFEST.MF中有Class-Path属性JarClassLoader 会同时将该属性声明的外部 JAR 包加入类加载路径按顺序加载外部依赖类。
核心特点JarClassLoader 仅加载当前 JAR 包及Class-Path声明的依赖与系统类加载器AppClassLoader隔离保证启动环境的独立性。
步骤 4通过 JarClassLoader 加载Main-Class指定的主类JarClassLoader 会根据Main-Class的全类名在 JAR 包中找到对应的 class 文件如com/example/DemoApplication.classJAR 包中类的路径与包结构一致并完成类的加载、链接、初始化类加载的三个阶段加载将 class 文件的二进制数据读入内存生成 Class 对象链接验证校验 class 文件合法性→ 准备为类变量分配内存→ 解析将符号引用转为直接引用初始化执行类的静态代码块、初始化静态变量完成类的初始化。
若主类加载失败如类不存在、依赖缺失、class 文件损坏会抛出ClassNotFoundException或NoClassDefFoundError异常启动终止。
步骤 5反射调用主类的public static void main(String[] args)方法主类加载完成后JVM 会通过Java 反射机制定位主类中的main方法核心要求是该方法必须满足固定签名java运行// 必须是 public static void参数为 String[]方法名严格为 main大小写敏感 public static void main(String[] args)JVM 会将命令行中 JAR 包后的参数如java -jar xxx.jar arg1 arg2封装为String[]数组传递给main方法并执行该方法此时程序正式启动进入业务逻辑执行阶段。
步骤 6程序运行与 JVM 生命周期绑定main方法是程序的「入口主线程」JVM 的生命周期会与该主线程绑定若主线程执行完毕无后台线程 / 守护线程JVM 会正常退出若主线程启动了其他用户线程如业务线程、定时任务JVM 会等待所有用户线程执行完毕后再退出若存在守护线程如垃圾回收线程守护线程会随 JVM 退出而终止。