本指南可以告诉您通过使用Gradle的 build init插件来生成Java库,这个Java库可以被用于其他JVM库或者应用。
您将构建什么
您将跟随Gradle的规约生成一个Java库文件。
您需要什么
1. 大概花费12分钟;
2. 一个text文本编辑器或者IDE;
3. JDK 1.8或以上版本;
4. Gradle分发包,5.0及以上版本;
创建一个库项目
Gradle 内置了一个build-in的插件,相关文档可以查看Gradle用户手册。这个插件提供了一个任务,称之为“init”,可以用它来生成项目。这个“init”(或者也叫“build-in”)任务也使用了“wrapper”任务去创建一个Gradle Wrapper脚本“gradlew”文件。
第一步需要创建一个文件夹作为新的项目并进入这个文件夹:
$ mkdir demo
$ cd demo
运行“init”任务
在新建的项目文件夹中,执行“init”任务并在他出现提示时选择“java-library”项目类型,对于其他的问题,直接按回车键使用其默认值就行。如下:
$ gradle init
> Task :wrapper
Select type of project to generate:
1: basic
2: application
3: library
4: Gradle plugin
Enter selection (default: basic) [1..4] 3
Select implementation language:
1: C++
2: Groovy
3: Java
4: Kotlin
5: Scala
6: Swift
Enter selection (default: Java) [1..6] 3
Select build script DSL:
1: Groovy
2: Kotlin
Enter selection (default: Groovy) [1..2] 1
Select test framework:
1: JUnit 4
2: TestNG
3: Spock
4: JUnit Jupiter
Enter selection (default: JUnit 4) [1..4]
Project name (default: demo):
Source package (default: demo):
> Task :init
Get more help with your project: https://docs.gradle.org/5.0/userguide/java_library_plugin.html
BUILD SUCCESSFUL
2 actionable tasks: 2 executed
如果您更喜欢使用Kotlin DSL,您可以选择kotlin作为您的构建脚本DSL。
“init”任务首先会执行“wrapper”任务去生成“gradlew”和“gradlew.bat”的wrapper脚本文件。创建的新项目结构如下:
Groovy DSL
├── build.gradle
├── gradle
│ └── wrapper ①
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
│ └── java ②
│ └── demo
│ └── Library.java
└── test
└── java ③
└── demo
└── LibraryTest.java
Kotlin DSL
├── build.gradle.kts
├── gradle
│ └── wrapper ①
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
└── src
├── main
│ └── java ②
│ └── demo
│ └── Library.java
└── test
└── java ③
└── demo
└── LibraryTest.java
① 生成的文件夹用于放置wrapper相关文件;
② 默认的Java资源文件夹;
③ 默认的Java测试类文件夹;
现在您已经拥有了一个简单 Java库项目所需的组件。
检查生成的项目文件
“ settings”文件被大量注释,但是仅仅有一行是未被注释。
Generated settings.gradle
rootProject.name = "building-java-libraries" ①
Generated settings.gradle.kts
rootProject.name = "building-java-libraries" ①
① 这里指定了根项目的名称
自动生成的build.gradle文件一样拥有很多内容。未被注释的部分在这里被复制(依赖关系的版本号可能会在Gradle的后续版本中更新)。
Generated build.gradle
plugins {
id 'java-library'
}
repositories {
jcenter() ①
}
dependencies {
api 'org.apache.commons:commons-math3:3.6.1' ②
implementation 'com.google.guava:guava:28.0-jre' ③
testImplementation 'junit:junit:4.12' ④
}
Generated build.gradle.kts
plugins {
`java-library`
}
repositories {
jcenter() ①
}
dependencies {
api("org.apache.commons:commons-math3:3.6.1") ②
implementation("com.google.guava:guava:28.0-jre") ③
testImplementation("junit:junit:4.12") ④
}
① 公共的二级制组件仓库;
② 这是导出给消费者的依赖项的一个例子,最终他们会在编译类路径中被找到;
③ 这是一个在内部使用的依赖项示例,而不是在消费者自己的编译类路径上公开;
④ JUnit 测试库依赖包;
这个构建脚本添加了一个“java-library”的插件,它是扩展自“java-base”插件的并增加了添加编译Java源代码的附加任务。
“src/main/java/demo/Library.java”的内容如下:
Generated src/main/java/demo/Library.java
package demo;
public class Library {
public boolean someLibraryMethod() {
return true;
}
}
生成的JUnit 测试类“src/test/demo/LibraryTest.java”内容如下:
Generated src/test/java/demo/LibraryTest.java
package demo;
import org.junit.Test;
import static org.junit.Assert.*;
public class LibraryTest {
@Test public void testSomeLibraryMethod() {
Library classUnderTest = new Library();
assertTrue("someLibraryMethod should return 'true'", classUnderTest.someLibraryMethod());
}
}
生成的测试类只有一个JUnit 4测试方法,这个测试方法用于实例化Library类,然后调用someLibraryMethod方法,并检查返回的值是否为' true '。
组装jar的库文件包
构建上面的项目,运行“build”任务,当一个项目包含有wrapper脚本时,您就可以使用规范的“gradle”命令,人们认为使用它是一种好的形式。
$ ./gradlew build
> Task :compileJava
> Task :processResources NO-SOURCE
> Task :classes
> Task :jar
> Task :assemble
> Task :compileTestJava
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :test
> Task :check
> Task :build
BUILD SUCCESSFUL
4 actionable tasks: 4 executed
第一次运行构建时,Gradle会检查您的~/.gradle目录下的缓存中是否已经有了JUnit库和其他列出的依赖项。如果没有,库将被下载并存储在那里,下一次运行构建时,将使用缓存的版本,然后“build”任务将会编译类、运行测试并生成测试报告。
您可以看到以下HTML输出文件的测试报告,它位于:build/reports/tests/test/index.html.一个简单的报告如下所示:
您可以在build/libs目录中找到新打包的JAR文件,其名称为demo.jar。运行以下命令验证存档是否有效:
$ jar tf build/libs/demo.jar
META-INF/
META-INF/MANIFEST.MF
demo/
demo/Library.class
您应该看到所需的清单文件-MANIFEST.MF -和编译后的Library.class文件。
恭喜您,您刚刚完成了创建 Java库的第一步!现在,您可以根据自己的项目需要对其进行自定义。
自定义JAR库
您通常希望JAR文件的名称包含库版本。这很容易通过在构建脚本中设置顶级版本属性来实现,如下所示:
build.gradle
version = '0.1.0'
build.gradle.kts
version = "0.1.0"
现在再次运行“jar”打包任务:
$ ./gradlew jar
> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :jar UP-TO-DATE
BUILD SUCCESSFUL
2 actionable tasks: 2 up-to-date
注意,在build/libs/demo-0.1. JAR中生成的JAR文件包含预期的版本号了。
另一个常见的需求是定制清单文件,通常通过添加一个或多个属性。让我们通过配置jar任务在清单文件中包含库名和版本。在构建脚本的末尾添加以下内容:
build.gradle
jar {
manifest {
attributes('Implementation-Title': project.name,
'Implementation-Version': project.version)
}
}
build.gradle.kts
tasks {
jar {
manifest {
attributes(
mapOf("Implementation-Title" to project.name,
"Implementation-Version" to project.version)
)
}
}
}
要确认这些更改按预期工作,再次运行jar任务,并且这一次也从jar中解压包查看manifest文件:
$ ./gradlew jar
$ jar xf build/libs/demo-0.1.0.jar META-INF/MANIFEST.MF
现在您看到的MAINIFEST.MF文件内容如下:
META-INF/MANIFEST.MF
Manifest-Version: 1.0
Implementation-Title: building-java-libraries
Implementation-Version: 0.1.0
现在,您可以通过尝试编译一些使用刚才构建的库的Java代码来完成这个练习。
添加API文档
“java-library”插件通过“javadoc”任务内置了对Java API文档工具的支持。
Build Init插件生成的代码已经在Library.java文件中添加了注释。将注释修改为“javadoc”标记,如下:
src/main/java/Library.java
/**
* This java source file was generated by the Gradle 'init' task.
*/
package demo;
public class Library {
public boolean someLibraryMethod() {
return true;
}
}
运行“javadoc”任务:
$ ./gradlew javadoc
> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :javadoc
BUILD SUCCESSFUL
2 actionable tasks: 1 executed, 1 up-to-date
您将会看到“javadoc”生成的文件,打开HTML文件,其路径如下:build/docs/javadoc/index.html.
总结
就像现在这样,您已经成功地构建了一个Java库项目,将其打包为一个JAR,并在一个单独的应用程序中使用它。在这个过程中,您已经学会了如何:
1. 创建一个Java库;
2. 调整生成的build.gradle并简单的结构化了Java文件;
3. 运行构建并查看测试报告;
4. 自定义JAR文件的名称和mainfest文件的内容;
5. 生成API文档;
下一步
构建一个库只是跨项目边界重用代码的一个方面。点击以下链接,您可能会有兴趣:
1. 使用JVM库;
2. 发布JVM库;
3. 让多模块(多项目)构建工作;