java如何启动应用程序、 -cp和-jar的区别、类加载过程

青旅半醒 2021-09-26 14:42 400阅读 0赞

java如何启动应用程序、 -cp和-jar的区别、类加载过程

文章目录

  • java如何启动应用程序、 -cp和-jar的区别、类加载过程
  • 问题1:如何通过java启动应用程序
    • 1、java classname
    • 2、java -jar jarName
    • 如何退出
    • 方式一 java [ options ] classname [ args ]
    • 方式二 java [ options ] -jar filename [ args ]
  • 问题2:java -cp 、-classpath为什么在 -jar 启动jar包无效
  • 问题3: -Xbootclasspath 、-Djava.ext.dirs、-cp区别、类加载过程
    • bootstrap loader
    • extension class loader
    • user class loader

问题1:如何通过java启动应用程序

两种方式:

1、java classname

java [ options ] classname [ args ]

2、java -jar jarName

java [ options ] -jar filename [ args ]

options 命令行选项由空格分隔。请参阅选项。
classname 要启动的类的名称。
filename 要调用的Java归档(JAR)文件的名称。仅与该-jar选项一起使用。
ARGS 传递给main()由空格分隔的方法的参数。类文件名或JAR文件名后面的参数传递给main()方法。

默认情况下,不是该java命令选项的第一个参数是要调用的类的完全限定名称。如果-jar指定了该选项,则其参数是包含应用程序的类和资源文件的JAR文件的名称。启动类必须Main-Class在其源代码中的清单标题中指明。

JRE在三组位置中搜索启动类(以及应用程序使用的其他类):
1、引导类路径(bootstrap classpath),
2、已安装的扩展(extent classpath)
3、用户的类路径(user application classpath)。

上图java启动类加载过程:
这里写图片描述
这里类的加载涉及到双亲委派机制。

如何退出

当启动器被错误的参数,严重错误或由JVM抛出的异常调用时,通常会由启动器返回以下退出值。但是,Java应用程序可能会选择使用API​​调用返回任何值System.exit(exitValue)。这些值是:0:成功完成 >0:发生错误

方式一 java [ options ] classname [ args ]

java -cp 和 -classpath 一样,是指定类运行所依赖其他类的路径,通常是类库,jar包之类,需要全路径到jar包,window上分号“;”分割,unix上“:”号分割。
格式:
java -cp .;myClass.jar packname.mainclassname
表达式支持通配符扫描某路径下所有jar包,例如:
java -cp .;c:\classes01\myClass.jar;c:\classes02*.jar packname.mainclassname
通配符说明:
包含星号(*)的类路径条目与类文件不匹配。要在单个目录中匹配类和JAR文件mydir,请使用mydir:mydir/或mydir/:mydir。选择的顺序决定了mydirJAR文件之前加载的类和资源是否被加载,mydir反之亦然。
子目录不会被递归搜索。例如,mydir/*搜索JAR文件只有在mydir,不mydir/subdir1,mydir/subdir2等。
##注意:

  1. -cp 和 -classpath 使用效果一样
  2. -多个启动程序可以引用相同jar进行启动程序
  3. Java解释器将按照它们出现在类路径变量中的顺序查找目录中的类

方式二 java [ options ] -jar filename [ args ]

启动含manifest的jar包,可以使用

  1. java -jar <jar-file-name>.jar

如果jar里没有 manifest,则可以使用
java -cp foo.jar full.package.name.ClassName
当main类依赖多个jar时,可以把多个jar打包到一个目录,
然后用-Djava.ext.dirs指定该目录,引用依赖的多个jar。如:
java -Djava.ext.dirs=<多个jar包的目录> com.test.HelloWordMain

也可以用-Xbootclasspath引导类路径方式引用 jar包依赖。使用方式如下:

  1. -Xbootclasspath: 完全取代基本核心的Java class 搜索路径. 不常用,否则要重新写所有Java 核心class
  2. -Xbootclasspath/a: 后缀在核心class搜索路径后面.常用
  3. -Xbootclasspath/p: 前缀在核心class搜索路径前面.不常用,避免

问题2:java -cp 、-classpath为什么在 -jar 启动jar包无效

注意:当您使用该-jar选项时,指定的JAR文件是所有用户类的来源(mainfest文件配置),而其他类路径设置将被忽略。
什么意思呢?
就是-jar 启动jar包方式。-classpath 、-cp参数将被忽略不生效,类似spring boot的jar启动应用就不能通过此方式设置类路径。

问题3: -Xbootclasspath 、-Djava.ext.dirs、-cp区别、类加载过程

bootstrap loader

-Xbootclasspath 设置的是引导类
语法如下:
(引用多个jar包请用分隔符,与classpath参数类似,unix使用:号,windows使用;号,这里以unix为例)
java -Xbootclasspath/a:/usrhome/thirdlib.jar: -jar yourJarExe.jar
扩展类加载过程:

  1. 加载平台类(如java.lang.Object,java.lang.Thread等)
  2. 从rt.jar加载类($ JRE_HOME / lib / rt.jar)
  3. -Xbootclasspath可用于更改引导类路径-Xbootclasspath / p:和-Xbootclasspath / a:可用于预先添加/追加其他引导目录 - 这样做时非常谨慎。在大多数情况下,您希望避免使用引导类路径进行播放。
  4. 在Sun的实现中,只读System属性sun.boot.class.path 被设置为指向引导类路径。请注意,在运行时不能更改此属性 - 如果更改了无效的值。
  5. 该加载器由Java null表示。即,例如,java.lang.Object.class。getClassLoader()会返回null(所以对于其他引导类如java.lang.Integer,java.awt.Frame,java.sql.DriverManager等)

extension class loader

在java命令中通过-Djava.ext.dirs指定扩展类目录
扩展类加载过程:

  1. 从已安装的可选包中加载类
  2. 从$ JRE_HOME / lib / ext目录下的jar文件加载类
  3. 系统属性java.ext.dirs可能被设置通过使用-Djava.ext.dirs命令行选项更改扩展目录。
  4. 在Sun的实现中,这是sun.misc.Launcher $ ExtClassLoader的一个实例(实际上它是sun.misc.Launcher类的内部类)。
  5. 以编程方式,您可以读取(只读!)系统属性java.ext.dirs以查找哪些目录用作扩展目录。请注意,您无法在运行时更改此属性 - 如果更改了无效的值。

使用方式:
Java exten class 存放在{Java_home}\jre\lib\ext目录下.当调用Java时,对扩展class路径的搜索是自动的.总会搜索的.这样,解决的方案就很简单了,将所有要使用的第三方的jar包都复制到ext 目录下.

user class loader

java命令设置方式:-cp -classpath设置
用户应用类加载过程:

  1. 从应用程序类路径加载类
  2. 使用应用程序类路径:环境变量CLASSPATH(或)、带有Java启动器的-cp或-classpath选项读取类路径
  3. 如果CLASSPATH和-cp都丢失,则“。” (当前目录)被使用。只读System属性java.class.path具有应用程序类路径的值。请注意,您无法在运行时更改此属性 。
  4. java.lang.ClassLoader.getSystemClassLoader()返回这个加载器
  5. 这个加载器也被(称为“系统类加载器”)(不会与加载Java“系统”类的引导加载器混淆)。
  6. 这是加载Java应用程序的“main”类(使用主要方法的类)的加载器。在Sun的实现中,这是sun.misc.Launcher $AppClassLoader的一个实例(实际上它是sun.misc.Launcher类的内部类)。
  7. 默认的应用程序加载器使用扩展加载器作为其父装载器。
  8. 您可以通过命令行选项-Djava.system.class.loader更改应用程序类加载器。该值指定java.lang.ClassLoader类的子类的名称。首先默认的应用程序加载器加载命名的类(并且这个类必须在CLASSPATH或-cp中)并创建它的一个实例。新创建的加载器用于加载应用程序主类。

java官方文档参考:
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/classpath.html#CBHHCGFB
https://blogs.oracle.com/sundararajan/understanding-java-class-loading

发表评论

表情:
评论列表 (有 0 条评论,400人围观)

还没有评论,来说两句吧...

相关阅读