写点什么

一篇文章搞定 java 中的 path 和 classpath

用户头像
shengjk1
关注
发布于: 2020 年 04 月 23 日

Path 作用

设置 path 是为了方便使用 java、javac等这些命令而不用写全路径。

如:

Classpath 的作用

jar 包的搜索路径,告诉应用程序去哪里寻找 class。默认为当前目录。在实际的应用时,一般不需要设置 classpath。

Classpath的使用方式

通配符

  1. 匹配所有 .jar 或者 .JAR

如 -cp mydir/* 用来查找 mydir 下所有 .jar或者.JAR结尾的文件。仅仅是查找 mydir 下的,不会去查找 mydir 子目录



  1. 匹配所有 .jar或者.JAR以及 class files (如:cat.class)

-cp mydir:mydir/ or mydir/:mydir 注意它们是有顺序的,mydir:mydir/* 会先加载 classes files 再加载 jar files

直接通过 jar 包

-cp mydir/a.jar:mydir/b.jar:mydir/c.jar

加载 class files

( 可以忽略,在实际项目中根本不会用这种方式,因为有 idea 等工具的存在,所以重点来体会一下工具为我们做了什么 )

目录结构

Java类不存在包引用

//package test;
/*
@author shengjk1
@date 2020/4/8
/
public class Test2 {
public static void main(String[] args) {
System.out.println("Hello Wrold");
}
}



Java类存在包引用

package test;
/*
@author shengjk1
@date 2020/4/8
/
public class Test2 {
public static void main(String[] args) {
System.out.println("Hello Wrold");
}
}







我们可以发现 java 以及 java -cp ./ 不管用了。发生了什么?
关键在于 package,package就表示在这个路径下去找这个类,当执行 java Test2 时,它会在 ./test 目录下查找,但根本就没有这个目录,故
Could not find or load main class

Java类存在包引用,通过指定 classpath 来执行

Java class 之间相互引用并通过命令行执行

通过 Test1.java 引用 Test2.java

package test;
import java.util.ArrayList;
/*
@author shengjk1
@date 2020/1/19
/
public class Test1 {
public static void main(String[] args) {
Test2.main(args);
}
}



Java class 引入第三方 jar 包并通过命令行执行

在 Test1 中引入第三方的依赖 kudu

package test;
import org.apache.kudu.client.KuduTable;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/*
@author shengjk1
@date 2020/1/19
/
public class Test1 {
public static void main(String[] args) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(192);
integers.add(191);
Map<String, SoftReference<KuduTable>> kuduTableMap = new HashMap<>();
Test2.main(args);
}
}



Classpath的应用场景

  1. 打包是没有指定主类,可以用java -cp xxx.jar 主类名称(绝对路径)

  2. 要引用其他的jar包,可以用java -classpath $CLASSPATH:xxxx.jar 主类名称(绝对路径)

Idea等工具究竟为我们做了什么

通过 Classpath的使用方式 我们知道了在命令行执行代码是何等的麻烦,而当我们使用idea的时候只需要



就可以运行一个包含 main 方法的 .java 文件,这是何等的简单。可是为什么呢?为什么这样就可以执行了?



通过上面的例子我们可以知道,要想正常的编译执行 .java 文件,需要两个条件:

  1. 必须的 jar 包,一部分是 JVM 所必须的 jar, 一部分是依赖的第三方包。

  2. class files 的正确路径

那么我们就来看一下 idea 是否满足这两个条件。



首先必须要有必须的 jar 这是 JVM 所必须的 jar



我们所依赖的 jar 也都被放进了 classpath,这也省的我们自己去手动一个个指定。



所以基本 jar 依赖的问题就解决了,

其次,我们需要正确的 class files 路径。



设置了 build 后的路径为 ${PROJECT_ROOT}/target。



设置了 target 的文件路径。通过这两个设置,保证我们自己写的.java 文件的正确路径。至此我们执行



它就可以正确的跑起来了。

参考

https://docs.oracle.com/javase/tutorial/essential/environment/paths.html

https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html

补充

就在刚刚我还好奇为什么一些程序,比如 Flink 。竟然可以不通过 java -jar 或者 java -cp 主方法 的方式来执行( 其实是通过 java -cp 主方法 的方式来执行的)。

我们修改一下 Flink 的启动脚本



# Add HADOOPCLASSPATH to allow the usage of Hadoop file systems
echo '========================================='
echo $JAVARUN
echo $JAVAARGS
echo ${logsetting[@]}
classpath=manglePathList "$CCCLASSPATH:$INTERNALHADOOPCLASSPATHS"
echo $classpath
echo '======================================='
exec $JAVARUN $JVMARGS "${logsetting[@]}" -classpath "manglePathList "$CCCLASSPATH:$INTERNALHADOOP_CLASSPATHS"" org.apache.flink.client.cli.CliFrontend "$@"

然后我们在执行一下,看看会发生什么?

这是 $JAVA_RUN

/mnt/jdk8/bin/java

这是 $JAVA_ARGS

空空如野

这是 ${log_setting[@]}

-Dlog.file=/mnt/software/flink-1.7.2/log/flink-wanghaoran-client-bigdata-dev-node-3.log -Dlog4j.configuration=file:/mnt/software/flink-1.7.2/conf/log4j-cli.properties -Dlogback.configurationFile=file:/mnt/software/flink-1.7.2/conf/logback.xml

这是 $classpath,加上了 hadoop conf

/mnt/software/flink-1.7.2/lib/flink-python2.11-1.7.2.jar:/mnt/software/flink-1.7.2/lib/flink-shaded-hadoop2-uber-1.7.2.jar:/mnt/software/flink-1.7.2/lib/log4j-1.2.17.jar:/mnt/software/flink-1.7.2/lib/slf4j-log4j12-1.7.15.jar:/mnt/software/flink-1.7.2/lib/flink-dist2.11-1.7.2.jar::/etc/hadoop/conf:



发布于: 2020 年 04 月 23 日阅读数: 85
用户头像

shengjk1

关注

还未添加个人签名 2018.04.26 加入

博客 https://blog.csdn.net/jsjsjs1789

评论

发布
暂无评论
一篇文章搞定 java 中的 path 和 classpath