我们从CLASSPATH环境变量说起,Java程序中依赖的jar包都是通过CLASSPATH进行查找的吗?
答案是否定的,从JAVA 查找类文件的官方文档中,我们看到的事实是这样:
Java启动程序,启动Java虚拟机,虚拟机按以下顺序搜索和加载类:
- Bootstrap类——包含Java平台的类,包括rt.jar中的类和jre/lib中几个其他重要的JAR文件。
- 扩展类——使用Java扩展机制的类。这些文件作为.jar文件捆绑在扩展目录jre/lib/ext中。
- 用户类——由开发人员和第三方定义的不利用扩展机制的类。您可以使用命令行上的-classpath选项(首选方法)或使用classpath环境变量来标识这些类的位置。
通常,我们只能指定用户类的位置,至于Bootstrap和拓展类会按照默认规则自动进行查找。
JAVA启动程序如何查找Bootstrap类
Bootstrap类库所在的路径被保存在虚拟机系统属性sun.boot.class.path中,通过该属性来查找Bootstrap类库。
JAVA启动程序如何查找拓展类
拓展类是被放在jre/lib/ext下的jar包或zip压缩包,通过一个叫JAVA拓展框架的东东进行加载。
JAVA启动程序如何查找用户类
JAVA启动程序通过classpath来查找用户类,classpath是指定包含.class文件的文件夹,jar包和zip文件的路径集合(每个jar包必须单独指定,指定包含多个jar包的文件夹是无效的,这是个问题),classpath的值被保存在java.class.path系统属性中。
java.class.path的值会通过如下方式设置:
- 默认为".",表示当前路径下的所有.class类文件(或者子文件夹下的类文件)
- CLASSPATH系统环境变量设置的值,将覆盖默认值。(因此CLASSPATH中会包含默认".")
- 在命令行中设置-cp或-classpath参数的值,将覆盖默认值和CLASSPATH的值
- 通过-jar参数指定jar时 ,将覆盖掉所有其他值,所需的类必须来自指定的jar包
问题来了,CLASSPATH中不能直接配置包含多个jar包的文件夹路径,只能单独配置每个jar包,怎么办呢?
众所周知,java中系统属性java.ext.dirs指定的目录由ExtClassLoader加载器加载,如果您的程序没有指定该系统属性(-Djava.ext.dirs=xxx/lib)那么该加载器默认加载$JAVA_HOME/lib/ext目录下的所有jar文件。但如果你手动指定系统属性且忘了把$JAVA_HOME/lib/ext路径给加上,那么ExtClassLoader不会去加载$JAVA_HOME/lib/ext下面的jar文件,这意味着你将失去一些功能。
所以,思路就是通过 -Djava.ext.dirs 设置拓展类,命令举例:javac -Djava.ext.dirs=lib Test.java,lib表示包含jar包的文件目录,这样一来,Java启动程序就会从设置的拓展类目录下查找所有的jar包了。
记得把原有路径jre/lib/ext保留或恢复哦,C:\Program Files\Java\jdk1.8.0_72>javac -Djava.ext.dirs=.\jre\lib\ext Test.java。