前言
最近又在研究 SpringBoot 源码(研究好几次了,研究完有些用不上就忘了😅),在 SpringBoot 执行 main 方法启动过程中,会根据 classpath 下的类信息推断当前环境信息。这里 classpath 究竟是指哪呢,搜了中文语境下的技术文章,竟然没有找到想要的回答,可能是问题太简单了。本篇记录下我的看法。
java 最基础的 classpath
classpath,顾名思义,就是指 .class 文件所在的路径。.class 文件由 .java 文件编译后产生,我们用 java 命令执行.class 文件时,需要指定 jvm 去哪搜索目标 class 文件,总不能全盘扫描对吧,而指定去哪搜索就是 classpath 的含义,即:classpath
是JVM用到的一个环境变量,它用来指示JVM如何搜索class
。
执行 java 命令时,通过java -classpath dir
或者简写为 java -cp dir
来指定,
如果命令中没有显式指定,则 jvm 在当前目录中查找,即默认为:java -cp .
。
可以在命令中指定多个classpath,Linux 下用:
分隔。jvm 会依次查找指定目录,查找到一个之后不再继续查找下一个,比如java -cp .:/usr/local:/tmp/work
。
jar 包的 classpath
我们工程中一般都会有很多 .class 文件,利用 jar 包可以将他们批量管理起来,像这样java -cp ./demo.jar boo.Helloworld
指定 jar 包为 classpath 的话,jvm 就会去这个 jar 包里面搜索需要的类。
jar包还可以包含一个特殊的/META-INF/MANIFEST.MF
文件,MANIFEST.MF
是纯文本,可以指定Main-Class
和其它信息。JVM会自动读取这个MANIFEST.MF
文件,如果存在Main-Class
,我们就不必在命令行指定启动的类名,而是用更方便的命令:
java -jar hello.jar
jar包还可以包含其它jar包,这个时候,就需要在MANIFEST.MF
文件里配置classpath
了。
在大型项目中,不可能手动编写MANIFEST.MF
文件,再手动创建zip包。Java社区提供了大量的开源构建工具,例如Maven,可以非常方便地创建jar包。
SpringBoot 特殊的 classpath
我们将一个基于 SpringBoot 和 Maven 开发的工程打成 jar 包,然后解压,可以看到这样的目录结构:
其中/META-INF/MANIFEST.MF
就是我们上文所述的可以指定Main-Class
的文件,我们打开看一下:
其中Main-Class
标识 SpringBoot 项目启动时,使用了自己的类JarLauncher
来加载 jar 包;
Spring-Boot-Classes
指定了 SpringBoot 项目的业务代码的文件夹路径;
Spring-Boot-Lib
指定了 SpringBoot 项目依赖的 jar 包的文件夹路径
我们打开文件夹进行验证,果然如此,SpringBoot 项目看来对搜索 jar 包的规则进行了改造:
在 IDEA 中启动应用时的 classpath
在 IDEA 等工具中运行 java 程序时,IDEA帮我们用命令行传入了我们依赖的所有 jar 包,这是我项目的命令,可以看出来非常多:
点开下图这行灰色的就能看到完整命令了: