使用Gradle编译Java项目

本文带你用Gradle编译一个简单的Java项目。

本文目标

创建一个简单的Java项目,然后用Gradle编译。

你需要

  • 15分钟左右
  • 文本编辑器或者IDE
  • JDK 8+

创建项目

我们首先需要创建项目一个Java项目。为了专注于Gradle的操作,这个Java项目越简单越好。

创建文件夹结构

在你选择的项目文件夹下面,创建子文件夹。
Windows系统的话,在命令行运行命令 :

mkdir src\main\java\hello

*nix系统的话,在运行命令 :

mkdir -p src/main/java/hello

最后文件夹结构如下:

└── src
    └── main
        └── java
            └── hello

src/main/java/hello文件夹下面,你可以按自己的想法创建任何Java类。为了简单起见,我们只创建两个类:HelloWorld.java和Greeter.java。

package hello;

public class HelloWorld {
	public static void main(String[] args) {
		Greeter greeter = new Greeter();
		System.out.println(greeter.sayHello());
	}
}
package hello;

public class Greeter {
	public String sayHello(){
		return "Hello world!";
	}
}

安装Gradle

现在你已经有一个可以编译的项目了,接下来我们开始安装Gradle。

我们可以用管理工具安装Gradle:

  • SDKMAN
  • Homebrew(使用brew安装gradle)

当然,如果你不想安装额外的工具软件,你可以从https://www.gradle.org/downloads上面直接下载gradle的二进制文件。我们只需要二进制文件,可以直接去找gradle-{version}-bin.zip文件来下载(例如gradle-6.5.1-bin.zip)。

下载下来之后,解压压缩包,然后把里面的bin文件夹添加到你的电脑的 高级系统设置 => 环境变量 => 系统变量 => path 里面。

为了测试Gradle是否安装成功,在你的项目根目录下面,用命令行运行命令:

gradle

如果安装成功,可以看到输出信息如下(版本号可能不同):


> Task :help

Welcome to Gradle 6.5.1.

To run a build, run gradle  ...

To see a list of available tasks, run gradle tasks

To see a list of command-line options, run gradle --help

To see more detail about a task, run gradle help --task 

For troubleshooting, visit https://help.gradle.org

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.5.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed

同时,项目根目录下面多了一个 .gradle 文件夹。

看看Gradle可以做什么

现在Gradle已经安装成功了,看看它可以做什么。在你创建项目编译配置文件 build.gradle 之前,你可以看看Gradle里面有什么任务可以用,运行如下命令:

gradle tasks

你可以看到一个可用任务的列表。假设你还没有添加 build.gradle 文件,你将看到一些非常基本的任务,如下:

> Task :tasks
> Connecting to Daemon
------------------------------------------------------------
Tasks runnable from root project
------------------------------------------------------------

Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.

Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'learn-gradle'.
components - Displays the components produced by root project 'learn-gradle'. [incubating]
dependencies - Displays all dependencies declared in root project 'learn-gradle'.
dependencyInsight - Displays the insight into a specific dependency in root project 'learn-gradle'.
dependentComponents - Displays the dependent components of components in root project 'learn-gradle'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'learn-gradle'. [incubating]
outgoingVariants - Displays the outgoing variants of root project 'learn-gradle'.
projects - Displays the sub-projects of root project 'learn-gradle'.
properties - Displays the properties of root project 'learn-gradle'.
tasks - Displays the tasks runnable from root project 'learn-gradle'.

To see all tasks and more detail, run gradle tasks --all

To see more detail about a task, run gradle help --task 

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.5.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed

尽管这些任务都是可用的,但是在没有项目编译配置文件的情况下,这些任务没有什么意义。随着你向build.gradle里面填充具体的内容,一些任务就会变得有用。

任务列表会随着你添加插件到build.gradle里面而变多,所以你偶尔可以运行tasks命令,看看都有什么任务可用。

说到添加插件,接下来我们添加一个插件,开启基本的Java编译功能。

编译Java代码

开始很简单,在你上面创建的根目录下面新建一个 build.gradle 文件,里面只写一行代码:

apply plugin: 'java'

这简单的一行代码在编译配置里面起很大的作用。重新运行 gradle task ,我们会看到任务列表里面添加的新的任务,包括编译相关的任务,生成JavaDoc的任务和运行测试的任务。

我们将会经常使用 gradle build 任务。这个任务编译,测试和打包字节码文件到一个JAR文件。你可以在命令行里面运行:

gradle build

几秒钟之后,就会显示 “BUILD SUCCESSFUL”,说明这次编译完成了。

为了查看编译的成果,我们看一下新生成的 build 文件夹。在里面我们可以看到多个文件夹,其中值得注意的有三个文件夹:

  • classes。项目源代码编译之后生成的.class文件。
  • libs。打包好的项目库文件(通常是JAR或者WAR文件)。

classes文件夹里面的.class文件都是通过编译Java源代码生成的。我们可以在里面找到HelloWorld.class和Greeter.class两个文件。

libs文件夹里面包含一个跟项目文件夹的名字一样的JAR文件。下一步,我们就可以看到怎么指定JAR文件的文件名和版本。

声明依赖

我们刚才创建的Hello World项目是完全自包含的,没有依赖额外的类库。但是,大部分的应用,都会使用外部的类库,来处理一些简单的或者复杂的功能。

比如说,我们除了输出"Hello World!",还想打印出当前日期和时间。Java自带的日期和时间工具库可以这个要求,但是你也可以使用一个外部的Joda Time库来实现这个功能。

首先,修改 HelloWorld.java

package hello;

import org.joda.time.LocalTime;

public class HelloWorld {
	public static void main(String[] args) {
		LocalTime currentTime = new LocalTime();
		System.out.println("The current local time is:" + currentTime);
		
		Greeter greeter = new Greeter();
		System.out.println(greeter.sayHello());
	}
}

我们在HelloWorld类里面,使用Joda Time的LocalTime类来获取和打印当前时间。

如果我们现在运行 gradle build 命令,编译过程会失败(提示错误:程序包org.joda.time不存在),因为你还没有声明Joda Time库作为一个编译时的依赖。

为了添加外部依赖,首先我们需要在 build.gradle 里面添加一个第三方的仓库源,如下:

repositories {
	mavenCentral()
}

repositories使编译系统从Maven Central仓库里面获取依赖库。Gradle严重依靠Maven编译工具已经建立的一些约定和工具,包括以Maven Central作为仓库源的这个选项。

现在我们已经准备好使用第三方库了,继续修改build.gradle

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
	compile "joda-time:joda-time:2.2"
	testCompile "junit:junit:4.12"
}

在dependencies块里面,我们声明一个Joda Time的依赖。我们的要求是(从右往左看):版本为2.2,名字为joda-time的库,在joda-time组里面。

另一个需要注意的是依赖的类型是 **compile ** ,说明编译时必须可用(如果你要打包成WAR文件,会包含到WAR文件的 /WEB-INF/libs 文件夹里面)。其他的需要在意的编译类型是:

  • providedCompile。编译项目源码的时候,需要这个依赖。但是运行项目的时候,由运行项目的容器提供该依赖。(例如:Java Servlet API)
  • testCompile。编译项目源码和运行项目的测试用例的时候,需要这个依赖。但是打包或者运行项目的执行代码时不需要。

最后,我们指定一下我们的JAR文件的名称:

jar {
	baseName = 'learn-gradle'
	version = '0.1.0'
}

jar代码块指定了JAR文件将会怎么命名。本例中,文件名将会变为 learn-gradle-0.1.0.jar

现在如果我们运行 gradle build 命令,Gradl会从Maven Central库中获取Joda Time依赖库,并且编译会运行成功。

使用Gradle Wrapper编译项目

Gradle Wrapper是开始一个Gradle项目的首选。它包含一个批处理脚本(在Windows中使用)和一个shell脚本(在OS X或者Linux中使用)。这些脚本使你可以不安装Gradle,也能运行一个Gradle项目。你只需要使用下面的命令:

$ gradle wrapper --gradle-version 6.5.1

执行完成之后,我们可以看到增加一些文件。两个脚本文件在根目录下面,而wrapper的jar包和properties文件则被添加到了gradle/wrapper文件下面。如下所示:

└── 
    └── gradlew
    └── gradlew.bat
    └── gradle
        └── wrapper
            └── gradle-wrapper.jar
            └── gradle-wrapper.properties

Gradle Wrapper已经可以用来编译我们的项目了。我们还可以把项目添加到版本控制系统中,而其他人可以复制你的项目然后编译它。使用Gradle Wrapper和安装了相同版本的Gradle的效果一样。运行wrapper脚本来执行编译任务,就像上面的操作那样:

gradlew build

或者

./gradlew build

控制台输出结果如下:

Downloading https://services.gradle.org/distributions/gradle-6.5.1-bin.zip
.........10%..........20%..........30%..........40%.........50%..........60%..........70%..........80%.........90%..........100%

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.5.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 1m 21s
2 actionable tasks: 2 up-to-date

在上面我们用–gradle-version设置了Gradle版本为6.5.1,所以Gradle首先下载并缓存了这个版本的Gradle二进制文件(如果已经缓存过,会直接使用缓存)。

Gradle Wrapper的设计目的就是为了直接提交到源码控制系统里面,使任何人都可以直接编译项目,而不用先安装Gradle再编译项目。同时可以配置使用特定版本的Gradle。

现在,你可以看到编译的成果如下:

├─classes
│  └─java
│      └─main
│          └─hello
│                  Greeter.class
│                  HelloWorld.class
│
├─generated
│  └─sources
│      ├─annotationProcessor
│      │  └─java
│      │      └─main
│      └─headers
│          └─java
│              └─main
├─libs
│      learn-gradle-0.1.0.jar
│
└─tmp
    ├─compileJava
    │      source-classes-mapping.txt
    │
    └─jar
            MANIFEST.MF

在里面,有我们所期望的class文件Greeter.class和HelloWorld.class,同时还有一个JAR文件。快速浏览一下JAR文件的内容:

$ jar tvf build\libs\learn-gradle-0.1.0.jar
     0 Sun Jul 12 16:43:56 CST 2020 META-INF/
    25 Sun Jul 12 14:52:16 CST 2020 META-INF/MANIFEST.MF
     0 Sun Jul 12 16:43:56 CST 2020 hello/
   369 Sun Jul 12 16:43:56 CST 2020 hello/Greeter.class
   987 Sun Jul 12 16:43:56 CST 2020 hello/HelloWorld.class

我们可以看到class文件已经被打包进去了。还有重要的一点,尽管你已经声明了joda-time库的依赖,但是这个库并没有包含到JAR文件里面。而且,这个JAR文件也不能执行。

为了使代码可以执行,我们可以使用gradle’s Gradle的 application 插件。添加如下代码到build.gradle里面:

apply plugin: 'application'

mainClassName = 'hello.HelloWorld'

接下来你可以运行程序了!运行命令:

gradlew run

或者

./gradlew run

结果如下:

> Task :run
The current local time is:17:55:34.598
Hello world!

Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.5.1/userguide/command_line_interface.html#sec:command_line_warnings

BUILD SUCCESSFUL in 2s
2 actionable tasks: 1 executed, 1 up-to-date

如果要打包项目里面的依赖包,需要对应的插件。比如说,我们打包成一个WAR文件,我们可以使用Gradle的WAR插件。如果我们使用Spring Boot,并且想要一个可执行的JAR文件的话,spring-boot-gradle-plugin这个插件就很方便满足我们的要求。具体操作就不在这一章中展开了。

整理之后,最终的 build.gradle 如下:

apply plugin: 'java'
apply plugin: 'application'

mainClassName = 'hello.HelloWorld'

repositories {
	mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
	compile "joda-time:joda-time:2.2"
	testCompile "junit:junit:4.12"
}

jar {
	baseName = 'learn-gradle'
	version = '0.1.0'
}

小结

你已经创建了一个简单但是有效的Gradle编译配置文件,可以正常的编译Java项目了。

源码下载

learn-gradle

参考资料

https://spring.io/guides/gs/gradle/

你可能感兴趣的:(Java教程,java)