环境变量CLASSPATH

在安装Java环境的时候,我们需要配置PATH和CLASSPATH。

  • PATH:PATH比较好理解,我们在命令行需要执行某个命令的时候如python的时候,如果没有配置PATH,则需要进入python.exe所在的文件夹下,然后执行python。那配置PATH中的python所在路径,其实就相当于简化了这个过程,当配置完成后再执行python,首先去PATH中从左到右搜索所有的路径,直到搜索到python.exe,然后利用该路径执行命令,如果找不到则提示该命令不存在。

  • CLASSPATH:CLASSPATH其实也很好理解,这里来一段Java官方文档的解释:

The CLASSPATH variable is one way to tell applications, including the JDK tools, * where to look for user classes *. (Classes that are part of the JRE, JDK platform, and extensions should be defined through other means, such as the bootstrap class path or the extensions directory.)

名如其人,classpath就是classes所在的path,那设置CLASSPATH的作用就是指定java类所在的目录,当我们执行java命令的时候,java需要去哪里找class文件呢,这时候就需要设置classpath,我们可以输出当前环境的classpath查看: * echo %CLASSPATH% *

1
.;C:\Program Files\Java\jdk1.8.0_181\lib;C:\Program Files\Java\jdk1.8.0_181\lib\tools.jar

CLASSPATH的扫描同样是从左向右的。我们可以看到参数以 ; 分割,那么第一个参数 *.*指代的就是当前目录,意思是java去当前目录下寻找class文件进行执行。

Spring中的classpath

我们在很多的项目代码的config代码中都可以看到 @PropertySource(value = "classpath:map-config.yaml") 类似的代码,在这里也用到了classpath,这里的classpath什么作用呢?

答案

你猜的没错,和环境变量的CLASSPATH作用相同,找class文件,上述例子中是寻找配置文件,CLASSPATH可以在启动命令上进行配置,配置完成后代码中会去扫描设置的CLASSPATH来寻找指定的配置文件。

例子

以组件的__service为例,这里面放的是Java的启动命令,在这里,我们可以找到关于CLASSPATH的使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#!/bin/bash
_ServerName=placeholder
JAVA_HOME=${JDK_PATH}
CLASSPATH=.:${JAVA_HOME}/lib/dt.jar:${JAVA_HOME}/lib/tools.jar
_Xms=4096M
_Xmx=8192M
_Xmn=2048M
_MetaspaceSize=2048M
_MaxMetaspaceSize=4096M
_DIR="$( cd "$(dirname "$0")" && pwd )"
_HOME_DIR=$(dirname "$_DIR")
_JSVC=${_HOME_DIR}/bin/linux/Jsvc
_Classpath=${CLASSPATH}:"${_HOME_DIR}/config":"${_HOME_DIR}/../../conf":"${_HOME_DIR}/lib/*"
_MainClass=com.xxx.xxx.Bootstrap
_StarCLASS=com.xxx.JsvcLauncher

_Pid=${_HOME_DIR}/temp/${_ServerName}.pid
#_LogOut=${_HOME_DIR}/logs/${_ServerName}.log
_LogOut=/dev/null
_LogErr=${_HOME_DIR}/logs/Jsvc.log

echo "service name: $_ServerName"

do_exec()
{
    $_JSVC -D${_ServerName} -home $JAVA_HOME -cwd ${_HOME_DIR}/config -Djava.net.preferIPv4Stack=true -Dcom.sun.jndi.ldap.connect.pool.protocol="plain ssl" -XX:MetaspaceSize=${_MetaspaceSize} -XX:MaxMetaspaceSize=${_MaxMetaspaceSize} -Xms${_Xms} -Xmx${_Xmx} -Xmn${_Xmn} -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Xloggc:${_HOME_DIR}/logs/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=8M -Djava.io.tmpdir=${_HOME_DIR}/temp -Dloader.main=${_MainClass}  -wait 60 -pidfile $_Pid -outfile ${_LogOut} -errfile ${_LogErr} -cp ${_Classpath} $1 ${_StarCLASS}
}
....

上述代码中有关CLASSPATH的部分为下面的代码

1
2
3
CLASSPATH=.:${JAVA_HOME}/lib/dt.jar:${JAVA_HOME}/lib/tools.jar
_Classpath=${CLASSPATH}:"${_HOME_DIR}/config":"${_HOME_DIR}/../../conf":"${_HOME_DIR}/lib/*"
${_Classpath}
  1. 第一行的CLASSPATH其实就是我们配置的环境变量CLASSPATH
  2. 第二行的_Classpath在引用了第一行的CLASSPATH的基础上又增加了三个
    • ${_HOME_DIR}/config 用来读取组件壳bin/xxx/config下的配置文件,如application.properties
    • ${_HOME_DIR}/../../conf 读取组件壳生成的config.properties等文件
    • ${_HOME_DIR}/lib/ 读取组件壳/bin/xxx/lib下的jar包
  3. 第三行是启动服务的时候添加的参数,将上述的_Classpath作为参数启动

实际案例解决

在启动xxx过程中,发现启动报错,找不到config.properties,排查发现,有引用的依赖的jar包中含有config.properties同名文件,其在/bin/xxx/lib目录下,而__service文件中,conf的设置顺序在config后,所以将conf的设置提前(根据从左向右扫描的顺序),至此解决问题。