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)
';