gradle学习(20)-详解java插件
最后更新于:2022-04-01 06:52:04
## 1.使用
在build.gradle中添加以下语句,表示插入java插件
~~~
apply plugin:'java'
~~~
## 2.source sets
java插件引入了sourceset这个概念,sourceset将编译时和执行时所要用到的source文件组合在一起,其中包含java的源文件和资源文件,有的插件还包括了groovy和Scala资源文件,sourceset与编译环境和运行环境都存在联系。
使用sourceset的目的是将一些源文件组合起来,为了某个特殊的目的在逻辑上进行分组。例如,你可能把测试的集合单独拿出来组合成一个sourceset,或者一些API啊,你项目中的实现类啊等等,都可以定义为一个sourceset。这只是个概念的问题,你知道知道你分组的意义:方便你管理文件。
java中定义了2个sourceset:一个是main group,还有一个是test group。
main:项目中的源文件,编译后组装到jar包中的。
test:项目的测试源码,例如JUint和TestNG写的测试代码。
## 3.任务
#### java plugin任务
**compileJava**:目的是编译java源文件,利用javac。依赖compile任务,属于JavaCompile类型。
~~~
apply plugin: 'java'
compileJava {
//enable compilation in a separate daemon process
options.fork = true
//enable incremental compilation
options.incremental = true
}
~~~
**processResource**:将项目的资源文件复制到项目class目录中。无依赖。属于Copy类型,严格来说是Copy的子类。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e4668005cc.jpg)
**classes** :组装class目录。依赖compileJava和processResource两个任务,还有一些编译的任务 。属于Task类型。
**compileTestJava**:编译测试源码,利用javac。依赖compile和一些产生测试编译环境的任务。属于JavaCompile类型。
**processTestResource**:将测试资源文件复制到项目class文件目录中。无依赖。属于Copy类型。
**testClasses**:组合测试的class目录。依赖compileTestJava和processTestResource和一些添加测试的编译任务。属于Task类型。
**jar**:组合成jar文件,依赖compile。属于Jar类型。
**javadoc**:生成java帮助文档,依赖compile。属于Javadoc类型。
**test**:执行测试case,依赖compile,compileTest等。属于Test类型
**uploadArchives**:上传存档文件。依赖那些在archives配置中产生镜像的任务,比如jar。属于UpLoad类型。
**clean**:删除build文件,使项目回归最原始状态.属于Delete类型。
**cleanTaskName**:删除由任务产生的文件,比如cleanJar就是删除有任务jar产生的文件,cleanTest就是删除由test产生的文件。属于Delete类型。
#### 专门处理sourceset的任务
**`compile<span class="replaceable">`SourceSet`</span>Java`**:利用javac编译sourceset定义的源文件,依赖所有产生sourceset编译类路径的任务。属于JavaCompile类型
**`process<span class="replaceable">`SourceSet`</span>Resources`**:将sourceset定义的资源文件复制到class目录中,无依赖,属于Copy类型。
**`<span class="replaceable">`sourceSet`</span>Classes`**:组合sourceset中定义的文件目录,依赖compileSourceSetJava和processSourceSetResources两个任务,属于Task类型。
#### 生命周期类任务
**assemble:**组合分析所有的档案文件。依赖所有的存档文件。属于Task类型。
**check:**执行所有的验证类任务,依赖所有验证类任务,包括test。属于Task类型。
**build:**执行构建,依赖check和assemble,属于Task类型。
**buildNeeded:**执行构建,依赖testCompile配置的子项目中build和buildNeeded任务,属于Task类型。
**buildDependents**:执行构建,依赖当前项目的子项目的build和buildDependents任务。属于Task类型。
**buildConfigName:**为特殊的配置类任务构建一个镜像,该任务都是隐式添加的。依赖configName代表的任务。属于Task类型。
**uploadConfigName**:为某一个配置任务分配镜像,然后上传镜像,该任务都是隐式添加的。依赖configName定义的任务,属于UpLoad类型。
#### 任务依赖关系图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e466815a49.jpg)
## 4.项目布局
java plugin规定一些项目目录的结构,但是下面的目录并不是要求必须存在。java在编译的时候,会访问下面所有的目录,如果不存在,会记住这些没有的目录。
**src/main/java**:java源文件
**src/main/resources**:项目资源文件
**src/test/java**:测试源文件
**src/test/resources**:测试资源文件
**src/sourceSet/java**:sourceset定义的java源文件,注意其中的sourceSet一级是根据sourceSet定义的目录名替换的。下同
**src/sourceSet/resourcs**:sourceset定义的资源文件
#### 修改上面默认的目录
通过下面的方式可以修改默认的目录结构,定义你自己想要的目录
~~~
sourceSets{
main{
java{
srcDir 'src/java'
}
resources{
srcDir 'src/resources'
}
}
}
~~~
这是sourceSets很重要的应用。
## 5.依赖管理
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e46682e1c2.jpg)
上面的图是从文档上截取下来的,它列举了任务之间的依赖关系,比如第一个compile是被compileJava所依赖的,即执行compile前,会先执行compile。所以要理解Name列是被依赖的任务,一般是全局任务,不是java插件特有的,而Used by tasks一般是plugin特有的。Extends则说明继承的任务,说明该任务是在被继承任务的基础上扩展的。
再来看另外一张图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e4668483ef.jpg)
上面的图更加的清晰展现出java任务和gradle任务之间的联系,浅蓝色的代表java任务,绿色代表gradle任务。用used by标注的代表箭头指向的任务使用了左边的任务。
而uploadArchives和archives之前的关系是uploads,说明uploadArchives依赖于archives任务,等archives任务生成存档文件后,uploadArchives就会把这些存档文件上传。
而jar 和archives、runtime之间的关系是,在后者执行的时候,jar任务会将定义的jar包添加其中。那么这个依赖关系到底怎么算,是说jar任务依赖runtime,还是runtime依赖jar呢,应该是jar依赖runtime。因为runtime其实不管你有没有jar任务,如果有才会将jar任务定义的东西执行,如果没有,也是不会影响它。但是jar任务就不同了,没有runtime,jar还有用么?
下面再来看看谁能sourceSet任务的依赖配置,于java plugin正常任务的图是一样的,就不多解释了。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e46685f19a.jpg)
## 6.常用属性
#### 目录属性
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e466871466.jpg)
目录属性都是成双成对出现,目录名+目录。目录名是一个文件夹的名称,相对于build目录,而目录则是加上build目录。一些默认值上面都列举出来,不想浪费时间一一列举了。
#### 其他属性
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e4668947d5.jpg)
比较重要的是sourceSets,包含了项目中定义的sourcesets,下面一节会详细介绍。archivesBaseName项目压缩包的名称。manifest操作MANIFEST文件的。
## 7.操作source set
(终于到了能写点代码的时候了)
#### 获取sourceset属性
~~~
apply plugin:'java'
println sourceSets.main.output.classesDir
println sourceSets['main'].output.classesDir
sourceSets{
println main.output.classesDir
}
sourceSets{
main{
println output.classesDir
}
}
sourceSets.all{
println name
}
~~~
执行gradle命令后输出:
~~~
D:\GRADLE~2\0112>gradle -q
D:\gradle_product\0112\build\classes\main
D:\gradle_product\0112\build\classes\main
D:\gradle_product\0112\build\classes\main
D:\gradle_product\0112\build\classes\main
main
test
Welcome to Gradle 2.2.1.
To run a build, run gradle <task> ...
To see a list of available tasks, run gradle tasks
To see a list of command-line options, run gradle --help
~~~
说明想要获得sourcesets中属性值的方法有很多种,上面的程序中就列举了4种。
#### 配置sourceset属性
~~~
apply plugin:'java'
sourceSets{
main{
java{
srcDir 'src/java'
}
resources{
srcDir 'src/resources'
}
}
}
println sourceSets.main.java.srcDirs
println sourceSets['main'].resources.srcDirs
sourceSets{
println main.java.srcDirs
}
sourceSets{
main{
println java.srcDirs
}
}
sourceSets.all{
println name
}
~~~
根据实际操作来看,我们只是添加了一个java目录和一个resources目录。
~~~
D:\GRADLE~2\0112>gradle -q
[D:\gradle_product\0112\src\main\java, D:\gradle_product\0112\src\java]
[D:\gradle_product\0112\src\main\resources, D:\gradle_product\0112\src\resources
]
[D:\gradle_product\0112\src\main\java, D:\gradle_product\0112\src\java]
[D:\gradle_product\0112\src\main\java, D:\gradle_product\0112\src\java]
main
test
Welcome to Gradle 2.2.1.
To run a build, run gradle <task> ...
To see a list of available tasks, run gradle tasks
To see a list of command-line options, run gradle --help
~~~
#### 设置sourcesets属性
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e4668abfc5.jpg)
上面的表格列举了一些sourceset重要的属性,其中的一些属性在之前的2个例子中也有涉及。
#### 定义新的sourceset属性
~~~
apply plugin:'java'
sourceSets{
intTest
}
dependencies {
intTestCompile 'junit:junit:4.11'
intTestRuntime 'org.ow2.asm:asm-all:4.0'
}
~~~
在上面的代码中,我们定义了一个新的属性,叫做intTest,然后定义了2个依赖任务intTestCompile和intTestRunTime。这个我们在第5节.依赖管理中讲过,sourceset的依赖管理中可以根据属性值设置任务,刚好可以回过头复习复习。执行下任务:
~~~
D:\GRADLE~2\0112>gradle intTestClasses
:compileIntTestJava UP-TO-DATE
:processIntTestResources UP-TO-DATE
:intTestClasses UP-TO-DATE
BUILD SUCCESSFUL
Total time: 2.699 secs
~~~
#### sourceset相关样例
~~~
apply plugin:'java'
sourceSets{
intTest
}
dependencies {
intTestCompile 'junit:junit:4.11'
intTestRuntime 'org.ow2.asm:asm-all:4.0'
}
//将intTest输出文件打成jar包
task intTestJar(type:Jar){
from sourceSets.intTest.output
}
//为intTest中所有的java文件生成java帮助文档
task intTestJavadoc(type:Javadoc){
source sourceSets.intTest.allJava
}
//为intTest添加测试
task intTest(type:Test){
testClassesDir = sourceSets.intTest.output.classesDir
classpath = sourceSets.intTest.runtimeClasspath
}
~~~
首先我们执行intTest任务:
~~~
D:\GRADLE~2\0112>gradle intTestJar
:compileIntTestJava UP-TO-DATE
:processIntTestResources UP-TO-DATE
:intTestClasses UP-TO-DATE
:intTestJar
BUILD SUCCESSFUL
Total time: 4.337 secs
~~~
会在build/libs目录下生成jar包
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e4668ca5e0.jpg)
然后我们执行intTestJavadoc来生成java帮助文档:
~~~
D:\GRADLE~2\0112>gradle intTestJavadoc
:intTestJavadoc UP-TO-DATE
BUILD SUCCESSFUL
Total time: 2.73 secs
~~~
执行成功,但是不会生成javadoc,因为我没有定义intTest具体细节
最后来执行测试
~~~
D:\GRADLE~2\0112>gradle intTest
:compileIntTestJava UP-TO-DATE
:processIntTestResources UP-TO-DATE
:intTestClasses UP-TO-DATE
:intTest UP-TO-DATE
BUILD SUCCESSFUL
Total time: 2.793 secs
~~~
## 8.Javadoc
任务javadoc是Javadoc类的一个实例,支持核心java文档选项和标准[doclet](http://unmi.cc/javadoc-customize-doclet/)格式,为了完整的继承这些特性,gradle定义了2个类:CoreJavadocOptions和StandardJavadocDocletOptions。详细信息也可以去这两个类中去查查。
javadoc中的一些属性:
**classpath**:执行环境,sourceSets.main.output代表的目录,以及sourceSets.main.compileClasspath代表的目录。是FileCollection的
**source**:源码文件目录,sourceSets.main.allJava代表的目录,是FileTree类型的。
**destinationDir**:生成的文档存放目录
**title**:项目的版本和名称
## 9.clean
该任务是Delete的一个实例,删除用dir描述的目录
## 10.Resources
是sourceset中的属性,一般是通过Copy处理资源相关信息。会被ProcessResources用到:
ProcessResources.srcDirs引用的是sourceSet.resources的值。
ProcessResources.destinationDir引用的是sourceSet.output.resourcesDir的值。
## 11.CompileJava
java plugin为项目中的每一个sourceset都提供一个CompileJava对象实例。在脚本中是下面的样式
~~~
apply plugin: 'java'
compileJava {
//enable compilation in a separate daemon process
options.fork = true
//enable incremental compilation
options.incremental = true
}
~~~
**classpath**:FileCollction,默认值是sourceSet.compileClasspath
**source**:FileTree,默认值是sourceSet.java
**destinationDir**:File.默认值是sourceSet.output.classesDir
## 12.增量式的java编译
该功能正在孵化中,以后有可能更改。
该功能的主要目的是
1.避免在编译了并不需要编译的源文件,提高编译的速度。
2.可能只是改变一点的输出,并不需要重新编译一些没有任何改变的目录。这一点对[JRebel](http://baike.baidu.com/link?url=JjWdQDfooN_XFDMP5Kd23QJX_T7qrzL-dKzc4OXp5aagOHyG0vUW1ofaf4GDOQvqj9OQ7qeroVAUDcsP4Jikb_)很有用。
这个功能肯定是一个高级且难以理解的东西,因为它涉及到底层的算法。所以我想我是不可能弄明白的了,且对我有啥用。只是知道有这么个东西就行。
## 13.Test
test任务是一个Test实例,它会自动识别和执行source set定义test目录下所有的单元测试,而且会生成测试报告(这个好像挺爽的啊,看来测试驱动开发看能能很容易的实现啦)。
支持JUnit和TestNG。
#### 测试执行
测试的执行是独立于JVM的,和构建的主进程也是分离的,其中关于jvm和运行时状态属性是可以通过API进行修改的。
1.你可以指定是否平行的执行测试。
2.你可以指定执行一定数量的case后重启执行进程。
3.设置case失败后的行为。
4.设置测试输出的log的等级。
#### 调试
可以通过Test.getDebug属性来让jvm进入5005端口,进入调试模式。而且你可以通过命令行模式参数--debug -jvm进入debug模式。
#### 测试过滤
从gradle1.0开始,就具备了执行某些特殊的case,或者根据匹配模式删选case来执行。可以做到以下几点过滤:
1.依据测试方法的等级过滤,执行一个单一的测试。
2.依据自定义的注解(以后实现)
3.依据测试的层次,执行继承某一个基础类的测试(以后实现)
4.依据一些运行时的规则,例如一些特殊的系统属性值或静态状态(以后实现)
说了这么多废话,如果在脚本中定义过滤条件呢?
~~~
test {
filter{
//方法名
includeTestsMatching "*UiCheck"
//包名过滤
includeTestsMatching "org.gradle.internal.*"
//整合的case
includeTestsMatching "*IntegTest"
}
}
~~~
也可以通过gradle命令行的参数来过滤:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e4668e0699.jpg)
#### 根据系统属性来执行单一测试
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e4668ee08a.jpg)
#### 测试检测
gradle可以自动识别出哪些class是测试类,如果做到的呢,在编译阶段,gradle观察这些编译的java类。而扫描哪些文件夹里的类,你可以去设置,包括哪些文件,不包括哪些文件,都可以自定义。而且它也会扫描出用JUnit和TestNG框架写的case。以JUnit为例来看看。
当使用JUnit的时候,我们会扫描junit3和junit4写的case。
1.类或超类继承与TestCase或者GroovyTestCase。
2.类或超类使用了@RunWith。
3.类或超类包含@Test注解的方法。
当使用TestNG的话,我们只扫描@Test注解的方法。
#### 测试分组
junit分组
~~~
test{
useJUnit{
includeCategories 'org.gradle.junit.CategoryA'
includeCategories 'org.gradle.junit.CategoryB'
}
}
~~~
TestNG分组
~~~
test{
useJUnit{
includeCategories 'org.gradle.junit.CategoryA'
includeCategories 'org.gradle.junit.CategoryB'
}
useTestNG{
excludeGroups 'integrationTests'
includeGroups 'unitTests'
}
}
~~~
#### 测试报告
gradle默认情况下生成下面3种报告:
1.HTML格式
2.XML格式
3.二进制
可以使用任务testReports来生成测试报告:
~~~
subprojects{
apply plugin:'java'
test{
reports.html.enabled = false
}
}
task testReport(type:TestReport){
destinationDir = file("$buildDir/report/allTest")
reportOn subprojects*.test
}
~~~
## 14.Jar任务
jar任务会将项目的源文件和资源文件打成jar包。
jar中manifest属性,定义了jar包的版本和名称。文件位于tmp//下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-07_568e46690818a.jpg)