本文概览:不使用maven情况下,使用原始Java命令进行编译打包。
1 编译
通过javac命令执行编译操作,将.java文件生成.class文件。
1、编译多个文件
假设有一个Model.java,Statisctis.java使用到Model.java类,此时可以通过 如下命令生成两个class。
1 |
javac -d ./ ./*.java |
2、相关参数
- -sourcepath <路径> :指定Java源文件的路径。
- -d <路径> :指定编译生成的.class文件存放目录。根据包名生成相应目录名。
- -cp 或者 -classpath <路径> 如果需要依赖外部jar,需通过该参数设置jar全路径。必须是*.jar不能是目录,多个时,使用冒号隔开
2 打包jar
jar就是一个归档工具,将生成编译生成clas文件生成一个jar。jar文件与 ZIP 文件唯一的区别就是在 JAR 文件的内容中,包含了一个 META-INF/MANIFEST.MF 文件,这个文件是在生成 JAR 文件的时候自动创建的。该文件的内容主要包括:
- Class-Path:指定执行运行jar时的classpath;
- Main-Class:指定运行时的main方法所在类;
如下是一个spring boot 的jar解压之后,在META-INFO/MANIFEST.MF文件内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Manifest-Version: 1.0 Implementation-Title: xxxxxxx Implementation-Version: 1.0.0 Built-By: dxm Implementation-Vendor-Id: com.xx.xxx Spring-Boot-Version: 2.0.4.RELEASE Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.xxx.MainClassName。 // 指定spring boot的入口类 entApplication Spring-Boot-Classes: BOOT-INF/classes/ // 项目的class文件目录 Spring-Boot-Lib: BOOT-INF/lib/ // 依赖的第三方jar包 Created-By: Apache Maven 3.5.4 Build-Jdk: 1.8.0_191 Implementation-URL: https://projects.spring.io/spring-boot/#/spring-bo ot-starter-parent/microservice-management/web-admin |
1、相关参数
(1)指定main-class
通过-m 来指定 。创建一个mainfest.txt,内容如下
1 |
Main-Class: com.test.Test |
此时通过 “-m mainfest.txt” 就指定main-class为Test。这个main-class信息会保存到jar的META-INF/MANIFEST.MF 文件中。
2、打包那些文件
在不考虑mvn父子工程情况(每一个子模块生成一个jar)下,每一个项目会成生一个jar。这个jar中项目可能会依赖很多第三方的jar,如guava,commons包。
(1)只打包项目中class。
可以将项目class生成一个jar,然后将项目jar和第三方jar文件都放到一个lib的目录下面,这个归类操作可以通过手动创建lib和拷贝jar操作,在执行时,将lib路径加入到环境变量中。
注意1:对于jdk的类,不会进行打包,所以说jar文件都需要执行jvm中,并且需要机器配置好环境变量。这样执行jar时就会找到相应JDK类。
注意2:当我们使用maven来构建项目时。
- 默认打包插件,只会将项目的clas生成一个jar文件。
- 需要通过assemble插件。可以实现将项目class生成一个jar文件,并和第三方jar文件放置在某一个目录中。如在hsb的项目中,只有配置文件和pom.xml,但是在执行package打包时,会将hsb源码jar打包进来放置到lib目录下面。
更多方式可以参考:https://blog.csdn.net/xb12369/article/details/79966633
(2)不仅包含项目的class文件,还把第三方jar都集成到项目的jar文件中。如spring boot最终就生成一个jar文件。
3 运行jar或class
通过java命令运行jar、class命令如下:
1 2 3 4 5 |
# 运行class。 java [options] classname [args] # 运行jar java [options] -jar filename [args] |
举例运行一个class的方式如下:
(1) 执行一个class
方式1 直接运行class。在class路径下直接执行
java file.Export 。注意要使用“包.类名称”格式。
方式2 通过执行jar中class。
运行jar文件中class。通过-cp指定这个jar
1 |
java -cp javatest.jar file.Export |
这种方式和”java -jar jar名称“有什么区别?在执行一个jar文件时,根据生成生成一个jar时,是否指定main-class分为如下两种情况:
- 如果没有指定main-class,此时如果通过-jar 执行jar文件时,会出现”no main manifest attribute, in xxx.jar”错误,需要通过如下方式指定入口class。
1 |
java -cp javatest.jar file.Export |
- 如果指定了main-class,则此时可以通过-jar 执行这个jar文件。
2、java命令参数
(1)基本参数
- -cp 和 -classpath 。-cp 和 -classpath 一样,是指定类运行所依赖全路径的jar包,多个使用冒号分割。必须是jar文件。
- -D<propertyName>=value。指定属性变量值
- -jar:指定运行的jar名字
(2)JVM相关参数
如-Xms 、-Xmx等参数
3、执行jar的流程
在执行jar过程有哪些途径加载第三方jar,实现在执行一个class时可以找到其依赖的class。
(1)通过-cp或者-classpath指定
1 2 3 |
for path in "$lib_dir"/*.jar; do CLASSPATH="$path:$CLASSPATH" done |
(2)打包时,通过在META-INFO/MANIFEST.MF指定classpath的路径。
注意:更多加载jar的流程可以参考 JVM类加载相关知识。
4 实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
package generic; import com.google.common.base.Splitter; import com.google.common.collect.Lists; import java.util.List; /** * Created by wuzhonghu on 17/6/21. */ public class Demo { public static void main(String[] args) { List<String> fieldList = Lists.newArrayList( Splitter.on(";").trimResults().splitToList("123")); System.out.printf(fieldList.size() + ""); } } |
1、执行编译
1 |
javac -d output/ -classpath /Library/maven/repository/com/google/guava/guava/20.0/guava-20.0.jar Demo.java |
(1)-d 指定输出目录为output ,在./output生成一个generic目录,包括Demo.class。
(2)-classpath 指定需要依赖的jar文件。如果不指定,就会报如下错误
1 2 3 4 5 6 |
Demo.java:3: 错误: 程序包com.google.common.base不存在 import com.google.common.base.Splitter; ^ Demo.java:4: 错误: 程序包com.google.common.collect不存在 import com.google.common.collect.Lists; ...... |
2、执行class
1 |
$ java generic.Demo |
错误信息如下
1 2 3 4 5 6 7 |
Exception in thread "main" java.lang.NoClassDefFoundError: com/google/common/base/Splitter at generic.Demo.main(Demo.java:16) Caused by: java.lang.ClassNotFoundException: com.google.common.base.Splitter at java.net.URLClassLoader.findClass(URLClassLoader.java:381) |
通过指定classpath,如下,但是,还是报上面的错误。
1 |
java -classpath /Library/maven/repository/com/google/guava/guava/20.0/guava-20.0.jar generic.Demo |
结论:当待执行的类依赖其他jar时,此时需要自己先生成jar,如下
(1) 生存jgeneric.ar
在output下面执行
1 |
jar cvf generic.jar ./* |
(2)执行命令。
多个jar使用冒号隔开。如下命令,此时可以正确的运行了。
1 |
java -classpath /Library/maven/repository/com/google/guava/guava/20.0/guava-20.0.jar:generic.jar generic.Demo |
注意:如果此时就一个独立类,没有任何依赖,如下Test.java,此时通过javac生成Test.class之后,可以通过”java Test”直接就可以运行了,不再需要创建一个jar包了。
1 2 3 4 5 |
public class Test { public static void main(String[] args) { System.out.println("test"); } } |