1. 基本配置
配置本地化的缓存仓库路径,Gradle是保存再用户目录(C 盘)
1.1. 环境变量
重点是 GRADLE_USER_HOME
这个配置
1.2. 更改镜像源
在 GRADLE_USER_HOME
目录中建立一个 init.gradle
文件,其内容如下:
allprojects{
repositories {
def ALIYUN_REPOSITORY_URL = 'http://maven.aliyun.com/nexus/content/groups/public'
def ALIYUN_JCENTER_URL = 'http://maven.aliyun.com/nexus/content/repositories/jcenter'
all {
ArtifactRepository repo ->
if(repo instanceof MavenArtifactRepository){
def url = repo.url.toString()
if (url.startsWith('https://repo1.maven.org/maven2')) {
project.logger.lifecycle "Repository ${repo.url} replaced by $ALIYUN_REPOSITORY_URL."
remove repo
}
if (url.startsWith('https://jcenter.bintray.com/')) {
project.logger.lifecycle "Repository ${repo.url} replaced by $ALIYUN_JCENTER_URL."
remove repo
}
}
}
maven {
url ALIYUN_REPOSITORY_URL
url ALIYUN_JCENTER_URL
}
}
}
1.3. IDEA配置Gradle
默认情况下,这里会显示我们配置的环境变量信息
1.4. 创建项目
这个与 Maven
比较相似。
1.5. 项目组成
|-- .gradle/ ------------基包
|-- build/ ------------基包
|-- src
| |-- main ------------JAVA代码
| |-- test ------------测试
|-- gradle/
|-- build.gradle ------------配置文件,与Maven POM相当
|-- gradlew
|-- settings.gradle
1.5.1. build.gradle'
//配置的是一个Java项目插件
plugins {
id 'java'
}
// 组织名称
group 'xyz.wongs'
//版本
version '1.0-SNAPSHOT'
//仓库管理
repositories {
mavenCentral()
}
//依赖库管理
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
1.5.2. 创建程序
执行失败
Testing started at 17:12 ...
> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :compileTestJava
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :test
expected:<I [Love J]ava> but was:<I []ava>
Expected :I Love Java
Actual :I ava
<Click to see difference>
junit.framework.ComparisonFailure: expected:<I [Love J]ava> but was:<I []ava>
at junit.framework.Assert.assertEquals(Assert.java:100)
at junit.framework.Assert.assertEquals(Assert.java:107)
at junit.framework.TestCase.assertEquals(TestCase.java:269)
at xyz.wongs.drunkard.msg.IntfMsgTest.testMsg(IntfMsgTest.java:20)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
at java.base/java.lang.Thread.run(Thread.java:834)
xyz.wongs.drunkard.msg.IntfMsgTest > testMsg FAILED
junit.framework.ComparisonFailure at IntfMsgTest.java:20
1 test completed, 1 failed
> Task :test FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///F:/Repertory/99_WCNGS/gradle/gradle/build/reports/tests/test/index.html
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at 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.3/userguide/command_line_interface.html#sec:command_line_warnings
BUILD FAILED in 3s
3 actionable tasks: 2 executed, 1 up-to-date
gradle build test
2. Web项
Gradle创建Web项目,需要有两部,第一个勾选 Java
,在选择 Web
,否则创建将不成功。
war{
archiveName("war3.war")
}
自定义 war
包名称。
3. 控制命令
通过 cmd
来熟悉 Gradle
保证当前路径下有 build.gradle
配置文件,这个与 Maven
相似。
命令行乱码问题:
- 编码:任务的概念完成,编写
build.gradle
,追加编码任务的配置。
tasks.withType(JavaCompile){
options.encoding("UTF-8")
}
团队合作,每个人环境设置不一样,造成执行失败
- 跳过测试:gradle build -x test
- 清空编译结果
clean
- 硬件资源丰富,开启多线程的并发编译,需要修改配置
GRADLE_USER_HOME
,创建gradle.properties
//守护方式,新版本默认都守护模式,配置意义不大
org.gradle.daemon=true
// 启用多线程工作环境
org.gradle.parallel=true
- WEB项目需要考虑不同的打包处理,例如
jar
、war
。
$ gradle jar
$ gradle war
- 获取执行报告信息
--profile
$ gradle build --profile
4. 整合Junit5
Junit5
开始 维护组织已经变更为 org.junit.jupiter
。
将依赖从一个变成三个依赖库(4.12之后,也是两个不同的依赖库存在)
Junit5 = Platform + Jupiter + Vintage
需要修改配置文件添加依赖
dependencies {
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.0'
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.7.0'
testCompile group: 'org.junit.vintage', name: 'junit-vintage-engine', version: '5.7.0'
testCompile group: 'org.junit.platform', name: 'junit-platform-launcher', version: '1.7.0'
}
gradle
默认还是集成 Junit4
,所以需要修改任务配置,追加测试任务的配置
test{
useJUnitPlatform()
}
Junit5
属于全新架构
5. Wrapper
与 Maven
相比, Maven
配置过于繁琐,所以 Gradle
操作提供一个 Gradle Wrapper
,利用这个概念,直接在项目中自带 Gradle
的处理环境。
任意目录执行
gradle wrapper
|--- gradlew.bat ------ Gradle Wrapper简写
|--- .gradle/
|--- gradle/
|---|--- wrapper/
|---|---|--- gradle-wrapper.jar
|---|---|--- gradle-wrapper.properties
利用 gradle wrapper
自定义 Gradle
版本,最明显的变化就是在 gradle-wrapper.properties
中 distributionUrl
的值发生变更。
gradle wrapper --gradle-version XXXX
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
6. 代码分析器
性能、构建环境、依赖库以及程序上的问题, build --scan
代码扫描工具。
gradle build --scan
上传远程服务器分析,这时候需要确认 yes,no
结果返回中:
Publishing build scan...
https://gradle.com/s/iwom6hxwikt5w
我们看到返回要给地址 https://gradle.com/s/iwom6hxwikt5w
这就是报告的完整路径,我们邮箱验证下,即可看到完整的报告。
开发者和服务器的运维人员只需要此报告,就可以无缝沟通。
7. Groovy语法
Groovy = java核心类库 + Python语法形式 + Ruby特点
7.1. Groovy配置
Gradle
自带 Groovy
处理解析工具,因此不需要单独安装 Groovy
。
如果想安装学习,深入了解 Groovy
,直接安装 apache-groovy-sdk-x.x.x.zip
压缩包。
解压后,配置下环境变量即可。
C:\Users\WONGS>groovy -v
Groovy Version: 3.0.7 JVM: 1.8.0_151 Vendor: Oracle Corporation OS: Windows 10
7.2. 交互式编程
Groovy
直接提供交互式编程,输入 groovysh
命令:
C:\Users\WONGS>groovysh
Groovy Shell (3.0.7, JVM: 1.8.0_151)
Type ':help' or ':h' for help.
-------------------------------------------------------------------------------
groovy:000>
7.3. 开发工具
groovyconsole
:不太好用,不推荐idea
:需要环境配置,在IDEA直接创建脚本工具。
在创建中一定要选择 groovy script
选项。
后缀为 Grovy.groovy
,依赖JDK版本为 1.8
,以后学习尽量以 LTS
为主
7.4. 基础语法
Python
可以 print "内容"
//python 2语法
print "trest" + " 漫威"
//python 3语法
println("trest" + " 漫威")
7.4.1. def关键字
java 1.10 提供一个 var 关键字,根据赋值的类型,自动推断类型
动态更改变量类型,这个与 Python
类型
7.4.2. 数据类型
7.4.2.1. 适配能力强
int msg2 =10
println("【4】"+msg2.getClass()+ "msg2 = "+msg2)
msg2 = 33.2
println("【5】"+msg2.getClass()+ "msg2 = "+msg2)
输出
【4】class java.lang.Integermsg2 = 10
【5】class java.lang.Integermsg2 = 33
7.4.2.2. 数据溢出
def intA = Integer.MAX_VALUE+1
printf("【intA】 = " + intA + " 【intA class】 = " + +intA.getClass())
7.4.2.3. 强制转换
7.4.3. 循环条件
7.4.4. 断言
def num =10
assert num ==100
Caught: Assertion failed:
assert num ==100
| |
10 false
Assertion failed:
assert num ==100
| |
10 false
at xyz.wongs.gry.synx.index.Grovy3.run(Grovy3.groovy:13)
Process finished with exit code 1
7.4.5. 三目运算
String msg ="groovy"
println("原始 [msg] = "+(msg!=null?msg:"WONGS"))
println("原始 [msg] = "+(msg?msg:"WONGS"))
println("原始 [msg] = "+(msg?:"WONGS"))
7.4.6. 范围运算
for
循环
int sun = 0
for(i in 0..100)
sun+=i
println("====>" + sun)
- 闭包处理函数,将每个当前参数使用
it
描述
('a'..'z').each {
print(it+",")
}
7.4.7. switch
与 java
中内容判断不同, Groovy
提供一个范围
def age =18
switch (age){
case 0..17:
println('未成年')
break
case 18..35:
println('青年')
break
case 36..59:
println('中年')
break
default:
println('老年')
break
}
7.4.8. 闭包
//1、闭包编写方式之一
def method={
return "WONGS.xyz"
}
println("[闭包] "+ method()+ " 类型是 "+ method.getClass())
//2、闭包编写方式之二:没有参数
def method={ ->
return "WONGS.xyz"
}
println("[闭包] "+ method()+ " 类型是 "+ method.getClass())
//3、闭包编写方式之三:参数
def method={ ->
return "WONGS.xyz"
}
println("[闭包] "+ method()+ " 类型是 "+ method.getClass())
//
def closMethod1={ String ww ->
return ww + "WONGS.xyz"
}
println("[closMethod1 闭包] "+ closMethod1("wwww."))
def closMetho2={ int ... args ->
def sum = 0
for(int i: args)
sum += i
return sum
}
println("[closMetho2 闭包] "+ closMetho2(1,2,3))
// it是 groovy 默认当前参数信息,有参数传递,该it就是描述当前参数;没有的话,则 it 就是 null
def closMetho3={
return "【当前反馈内容】 WONGS" + it
}
println("[closMetho3 闭包] "+ closMetho3())
println("[closMetho3 闭包] "+ closMetho3("www."))
// 可以省略 return
def closMetho4={
"【当前反馈内容】 WONGS" + it
}
println("[closMetho3 闭包] "+ closMetho4())
println("[closMetho3 闭包] "+ closMetho4("www."))
闭包的类型
[闭包] WONGS.xyz 类型是 class xyz.wongs.gry.synx.index.Grovy7$_run_closure1
7.4.9. 主方法
只需要一个 static
static void main(String[] args){
def closMethod1 = {
it + " wongs.xyz"
}
println(closMethod1("wwww"))
}
7.4.10. 数组&列表
程序中的集合主要由数组、列表、Map
- 数组
// 数组
int[] arrays = new int[]{10,28,45,27,2}
Arrays.sort(arrays)
println(" 直接输出数组"+ arrays)
println(" Arrays 数组转换"+ Arrays.toString(arrays))
// 断言当前数组是否为整型数组
assert arrays instanceof int[]
println(" 获取数组长度 "+ arrays.length)
println(" 首个元素 "+ arrays.first() + " ;最后元素 "+ arrays.last())
- 列表
列表可以看作是 Java
中 LIST
def list = ["WONGS","@","QQ.COM"]
// 2.1 添加元素
list << "QQ邮箱"
list.add("163邮箱")
println("打印列表 "+ list)
// 2.2 迭代
list.each {
println("列表内容 -> "+it)
}
list.eachWithIndex{ entry, i ->
println(i+" 列表内容 -> "+entry)
}
- Set
參考 List
唯一區別就是需要手工為它設置具體的類型定義,同時也保留了 Set
不允許重複項的設定。
def sets = ["WONGS@QQ.COM","WCNGS@163.COM","IWCNGS@GMAIL.COM","WONGS@QQ.COM","WONGS@HOTMAIL.COM"] as Set
println("Clazz is "+ sets.class)
sets.eachWithIndex{ entry, i ->
println(i+" 列表内容 -> "+entry)
}
保存的順序為 LinkedHashSet
,這一點需要考慮的。
Clazz is class java.util.LinkedHashSet
0 列表内容 -> WONGS@QQ.COM
1 列表内容 -> WCNGS@163.COM
2 列表内容 -> IWCNGS@GMAIL.COM
3 列表内容 -> WONGS@HOTMAIL.COM
- Map
def maps = [QQ:"WONGS@QQ.COM",163:"WCNGS@163.COM",GMAIL:"IWCNGS@GMAIL.COM"]
println("Clazz is "+ sets.class)
// 遍歷
println("遍歷 1 "+ maps['163'])
println("遍歷 2 "+ maps.QQ)
// 添加元素
maps << [189:"189@189.COM"]
// 迭代
maps.eachWithIndex{ entry, i ->
println("index= "+ i+" ,Key = "+entry.getKey()+" ;Value = "+ entry.getValue())
}
- 集合嵌套
def listMaps =[
[QQ:"IWONGS@QQ.COM",GMAIL:"IWCNGS@GMAIL.COM"],
[QQ:"WONGS@QQ.COM",163:"WCNGS@163.COM"],null
]
println("打印内容 "+ listMaps)
// 获取指定 数据key的内容
println("打印内容 "+ listMaps.QQ)
// 可以匹配最后的 null
println("打印内容 "+ listMaps*.QQ)
7.4.11. 字符串操作
普通字符串 不关心双引号还是单引号,但是再插值字符串必须使用双引号进行定义
- 字符比较
// 1、字符比较,区分大小写的比较
def str1 = "WONGS@QQ.COM"
def str2 = "WONGS@QQ.COM"
println("【==比较】 "+ (str1==str2))
println("【equals比较】 "+ (str1.equals(str2)))
- 多行字符
// 2、多行字符串
def str3 = """
邮箱:
WONGS@QQ.COM
主题内容:我喜欢睡觉
"""
println("打印 "+ str3)
// 避免打印过程中第一行出现一个空格 , \ 实现命令结构的拆分操作
def str4 = """\
邮箱:
WONGS@QQ.COM
主题内容:我喜欢睡觉
"""
println("打印 "+ str4)
- 插值计算
// 3、插值计算
def str5 = "WONGS@QQ.COM"
def str6 = "WONGS@163.COM"
def str7 = "WONGS@GMAIL.COM"
def str8 = "打印 ${str5}+ ${str6}+ ${str7}"
println(str8)
- map 填充
// 4、Map填充
def maps = [QQ:"WONGS@QQ.COM",net:"WCNGS@163.COM",GMAIL:"IWCNGS@GMAIL.COM"]
def str9 = "打印 ${maps.QQ}+ ${maps.net}+ ${maps.GMAIL}"
println("【模式1】"+ str9)
def str10 = "打印 $maps.QQ+ $maps.net+ $maps.GMAIL"
println("【模式2】"+str10)
- 转义
// 5、转义字符
def info = [QQ:"WONGS@QQ.COM",net:"WCNGS@163.COM",GMAIL:"IWCNGS@GMAIL.COM"]
def str11 =$/\
"打印 ${maps.QQ}+ ${maps.net}+ ${maps.GMAIL}
年薪:19$$
/$
println("【转义字符】"+str11)
- 正则表达式
// 6、正则表达式
def reg = /\d+/
println("213".matches(reg))
7.4.12. 类
- 定义
构造方法不需要强制定义,使用时候按照属性要求设置响应内容即可;同时获取属性的时候直接用属性名完成属性内容的获取。
// 1、类定义
class Persion{
private String name
private int age
def getName(){
return this.name
}
}
p = new Persion(name:"WONGS")
println("【类定义】"+ p.getName())
- 对象集合
// 2、对象集合
def persons =[
new Persion(name:"WONGS"),
new Persion(name:"Zhang")
]
def handle(msg){
println("【handle函数处理】"+ msg.@name)
}
// 利用each 闭包特点,将迭代的数据内容传递到 handle(msg)函数中
persons.each {this.&handle}
// 输出全部集合中指定属性内容
println(persons*.getName())
7.4.13. 文件操作
- 文件写入
baseDir = new File('D:'+File.separator)
new File(baseDir,'mes.txt')
- 文件读取
new File(baseDir,'mes.txt').eachLine {
println(it)
}
new File(baseDir,'mes.txt').eachLine(){data,it->
println("【行号】"+it+ " ;内容 "+ data)
}
- 目录遍历
baseDir = new File('D:'+File.separator)
baseDir.eachFileMatch(~/.*\.txt/){
println("【遍历目录】"+it.getName())
}
7.4.14. 多线程
- 实现
// 1、实现
println("【多线程】 主线程名 "+Thread.currentThread().getName())
Thread.start {
println("【多线程】 子线程名 "+Thread.currentThread().getName())
'WONGS'.each {
print(it+'\t')
}
}
- Timer线程
// 2、Timer线程
new Timer().runAfter(10){
for (int x=0;x<10;x++){
println("【多线程】 Timer线程 "+Thread.currentThread().getName())
}
}
- 线程同步
def ticks = 20
def sale ={->
synchronized (this){
TimeUnit.SECONDS.sleep(2)
println("【多线程】 线程同步 "+Thread.currentThread().getName()+" 】 ,当前剩余票数 "+ ticks--)
}
}
for (i in 1..<10) {
def start = Thread.start(sale)
start.name='Saler - '+i
}
- JUC操作
CountDownLatch cdl = new CountDownLatch(1)
def first = Thread.start {
// 第一个线程等待同步
cdl.await()
println("【多线程】 First "+Thread.currentThread().getName())
}
def second = Thread.start {
// 第二个线程 解锁
TimeUnit.SECONDS.sleep(2)
println("【多线程】 Second "+Thread.currentThread().getName())
cdl.countDown()
}
// 先启动第一个线程
first
// 再启动第二个线程
second
我们看下效果输出
【多线程】 Second Thread-2
【多线程】 First Thread-1
- 线程池
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
for (i in 1..<20) {
executorService.submit(()->{
println("【多线程】 线程池 "+Thread.currentThread().getName()+" 序号 "+i)
})
}
8. Gradle任务
- 任务列表
gradle -q tasks
看到所有任务列表
14:26:44: Executing task 'tasks --quiet'...
Starting Gradle Daemon...
Gradle Daemon started in 2 s 904 ms
------------------------------------------------------------
Tasks runnable from root project
------------------------------------------------------------
Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
jar - Assembles a jar archive containing the main classes.
testClasses - Assembles test classes.
war - Generates a war archive with all the compiled classes, the web-app content and the libraries.
Build Setup tasks
-----------------
init - Initializes a new Gradle build.
wrapper - Generates Gradle wrapper files.
Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.
Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'gradle'.
components - Displays the components produced by root project 'gradle'. [incubating]
dependencies - Displays all dependencies declared in root project 'gradle'.
dependencyInsight - Displays the insight into a specific dependency in root project 'gradle'.
dependentComponents - Displays the dependent components of components in root project 'gradle'. [incubating]
help - Displays a help message.
model - Displays the configuration model of root project 'gradle'. [incubating]
outgoingVariants - Displays the outgoing variants of root project 'gradle'.
projects - Displays the sub-projects of root project 'gradle'.
properties - Displays the properties of root project 'gradle'.
tasks - Displays the tasks runnable from root project 'gradle' (some of the displayed tasks may belong to subprojects).
Verification tasks
------------------
check - Runs all checks.
test - Runs the unit tests.
Rules
-----
Pattern: clean<TaskName>: Cleans the output files of a task.
Pattern: build<ConfigurationName>: Assembles the artifacts of a configuration.
Pattern: upload<ConfigurationName>: Assembles and uploads the artifacts belonging to a configuration.
To see all tasks and more detail, run gradle tasks --all
To see more detail about a task, run gradle help --task <task>
14:27:10: Task execution finished 'tasks --quiet'.
- 所有属性
gradle -q properties
14:29:30: Executing task 'properties --quiet'...
------------------------------------------------------------
Root project
------------------------------------------------------------
allprojects: [root project 'gradle', project ':gradle-war3']
ant: org.gradle.api.internal.project.DefaultAntBuilder@7bb06ea9
antBuilderFactory: org.gradle.api.internal.project.DefaultAntBuilderFactory@9dc130d
archivesBaseName: gradle
artifacts: org.gradle.api.internal.artifacts.dsl.DefaultArtifactHandler_Decorated@42339fa
asDynamicObject: DynamicObject for root project 'gradle'
autoTargetJvmDisabled: false
baseClassLoaderScope: org.gradle.api.internal.initialization.DefaultClassLoaderScope@3c61b53b
buildDir: F:\Repertory\99_WCNGS\gradle\gradle\build
buildFile: F:\Repertory\99_WCNGS\gradle\gradle\build.gradle
buildPath: :
buildScriptSource: org.gradle.groovy.scripts.TextResourceScriptSource@44dc4138
buildscript: org.gradle.api.internal.initialization.DefaultScriptHandler@2df166d5
childProjects: {gradle-war3=project ':gradle-war3'}
class: class org.gradle.api.internal.project.DefaultProject_Decorated
classLoaderScope: org.gradle.api.internal.initialization.DefaultClassLoaderScope@30007678
compileJava: task ':compileJava'
compileTestJava: task ':compileTestJava'
components: SoftwareComponentInternal set
configurationActions: org.gradle.configuration.project.DefaultProjectConfigurationActionContainer@179c52e
configurationTargetIdentifier: org.gradle.configuration.ConfigurationTargetIdentifier$1@278a91b8
configurations: configuration container
convention: org.gradle.internal.extensibility.DefaultConvention@16b9c52
defaultArtifacts: extension 'defaultArtifacts'
defaultTasks: []
deferredProjectConfiguration: org.gradle.api.internal.project.DeferredProjectConfiguration@326b99b1
dependencies: org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler_Decorated@7df46a67
dependencyLocking: org.gradle.internal.locking.DefaultDependencyLockingHandler_Decorated@e803330
depth: 0
description: null
displayName: root project 'gradle'
distsDir: F:\Repertory\99_WCNGS\gradle\gradle\build\distributions
distsDirName: distributions
distsDirectory: property(org.gradle.api.file.Directory, map(org.gradle.api.file.Directory property(org.gradle.api.file.Directory, fixed(class org.gradle.api.internal.file.DefaultFilePropertyFactory$FixedDirectory, F:\Repertory\99_WCNGS\gradle\gradle\build)) org.gradle.api.internal.file.DefaultFilePropertyFactory$PathToDirectoryTransformer@5354b7be))
docsDir: F:\Repertory\99_WCNGS\gradle\gradle\build\docs
docsDirName: docs
ext: org.gradle.internal.extensibility.DefaultExtraPropertiesExtension@3d1c0a74
extensions: org.gradle.internal.extensibility.DefaultConvention@16b9c52
fileOperations: org.gradle.api.internal.file.DefaultFileOperations@6365e8e2
fileResolver: org.gradle.api.internal.file.BaseDirFileResolver@6c734e0d
gradle: build 'gradle'
group: xyz.wongs
identityPath: :
inheritedScope: org.gradle.internal.extensibility.ExtensibleDynamicObject$InheritedDynamicObject@1a6ced7a
java: extension 'java'
javaInstalls: org.gradle.jvm.toolchain.internal.DefaultJavaInstallationRegistry@477e1be9
layout: org.gradle.api.internal.file.DefaultProjectLayout@b10d91c
libsDir: F:\Repertory\99_WCNGS\gradle\gradle\build\libs
libsDirName: libs
libsDirectory: property(org.gradle.api.file.Directory, map(org.gradle.api.file.Directory property(org.gradle.api.file.Directory, fixed(class org.gradle.api.internal.file.DefaultFilePropertyFactory$FixedDirectory, F:\Repertory\99_WCNGS\gradle\gradle\build)) org.gradle.api.internal.file.DefaultFilePropertyFactory$PathToDirectoryTransformer@7de5ed55))
listenerBuildOperationDecorator: org.gradle.configuration.internal.DefaultListenerBuildOperationDecorator@1fd8ae
logger: org.gradle.internal.logging.slf4j.OutputEventListenerBackedLogger@37893a17
logging: org.gradle.internal.logging.services.DefaultLoggingManager@3a5ccdc3
model: project :
modelIdentityDisplayName: null
modelRegistry: org.gradle.model.internal.registry.DefaultModelRegistry@68811098
modelSchemaStore: org.gradle.model.internal.manage.schema.extract.DefaultModelSchemaStore@16257f8e
module: org.gradle.api.internal.artifacts.ProjectBackedModule@2bd1d598
mutationState: project :
name: gradle
normalization: org.gradle.normalization.internal.DefaultInputNormalizationHandler_Decorated@6882b6df
objects: org.gradle.api.internal.model.DefaultObjectFactory@34ec5cd9
org.gradle.daemon: true
org.gradle.parallel: true
parent: null
parentIdentifier: null
path: :
pluginManager: org.gradle.api.internal.plugins.DefaultPluginManager_Decorated@54098f0c
plugins: [org.gradle.api.plugins.HelpTasksPlugin@696d430c, org.gradle.buildinit.plugins.BuildInitPlugin@142434b0, org.gradle.buildinit.plugins.WrapperPlugin@4278a879, org.gradle.language.base.plugins.LifecycleBasePlugin@5a913ed5, org.gradle.api.plugins.BasePlugin@59e773a8, org.gradle.api.plugins.ReportingBasePlugin@6c535d90, org.gradle.api.plugins.JavaBasePlugin@6bef1b03, org.gradle.api.plugins.JavaPlugin@38dbe73d]
processOperations: org.gradle.process.internal.DefaultExecActionFactory$DecoratingExecActionFactory@5a43a9bd
project: root project 'gradle'
projectConfigurator: org.gradle.api.internal.project.BuildOperationCrossProjectConfigurator@2c8ad0b8
projectDir: F:\Repertory\99_WCNGS\gradle\gradle
projectEvaluationBroadcaster: ProjectEvaluationListener broadcast
projectEvaluator: org.gradle.configuration.project.LifecycleProjectEvaluator@3faef129
projectPath: :
projectRegistry: org.gradle.api.internal.project.DefaultProjectRegistry@58ab0bee
properties: {...}
providers: org.gradle.api.internal.provider.DefaultProviderFactory_Decorated@1f624f07
publicType: org.gradle.api.plugins.BasePluginConvention
reporting: extension 'reporting'
reportsDir: F:\Repertory\99_WCNGS\gradle\gradle\build\reports
repositories: repository container
resources: org.gradle.api.internal.resources.DefaultResourceHandler@65974343
rootDir: F:\Repertory\99_WCNGS\gradle\gradle
rootProject: root project 'gradle'
script: false
scriptHandlerFactory: org.gradle.api.internal.initialization.DefaultScriptHandlerFactory@2d78d161
scriptPluginFactory: org.gradle.configuration.ScriptPluginFactorySelector@2d8c4b5b
serviceRegistryFactory: org.gradle.internal.service.scopes.ProjectScopeServices$$Lambda$331/356341777@201b339a
services: ProjectScopeServices
sourceCompatibility: 1.8
sourceSets: SourceSet container
standardOutputCapture: org.gradle.internal.logging.services.DefaultLoggingManager@3a5ccdc3
state: project state 'EXECUTED'
status: integration
subprojects: [project ':gradle-war3']
targetCompatibility: 1.8
taskThatOwnsThisObject: null
tasks: task set
test: task ':test'
testReportDir: F:\Repertory\99_WCNGS\gradle\gradle\build\reports\tests
testReportDirName: tests
testResultsDir: F:\Repertory\99_WCNGS\gradle\gradle\build\test-results
testResultsDirName: test-results
version: 1.0-SNAPSHOT
14:29:31: Task execution finished 'properties --quiet'.
8.1. 任务定义
在 build.gradle
中添加任务,添加完任务,我们在右边的 other
中看到我们定义的任务,如果看不到重新编译下。
task wongs{
println("当前任务 WONGS")
}
8.1.1. 任务执行
执行
- 命令行执行
gradle wongs
- 点击按钮
如图
8.1.2. 任务定义方法
接口常量信息
public interface Task extends Comparable<Task>, ExtensionAware {
String TASK_NAME = "name";
String TASK_DESCRIPTION = "description";
String TASK_GROUP = "group";
String TASK_TYPE = "type";
String TASK_DEPENDS_ON = "dependsOn";
String TASK_OVERWRITE = "overwrite";
String TASK_ACTION = "action";
String TASK_CONSTRUCTOR_ARGS = "constructorArgs";
Task
接口实例之后,就需要配置
- 基础语法
def task = task(wongsTask)
task.doLast {
println("Task I Like Gradle")
}
- 任务属性设置
def task = task(description:" Xyz.WONGS",wongsTask)
task.doLast {
println("Task I Like Gradle")
}
结果并没有描述信息
> Task :wongsTask
Task I Like Gradle
gradle help --task wongsTask
这时候我们看输出项的内容非常丰富。
14:52:31: Executing tasks 'help --task wongsTask'...
> Task :help
Detailed task information for wongsTask
Path
:wongsTask
Type
Task (org.gradle.api.Task)
Description
Xyz.WONGS
Group
-
这些描述信息可以在任务详情帮助进行详细的显示操作。
- 闭包机制
闭包创建 gradle
任务
task yo{
description('自定义机制')
group('xyz.wongs')
doLast {
println('WONGS:www.baidu.com')
}
}
- 其他常见方式
task(wons){
description('OUS')
group('xyz.wongs')
doLast {
println('WONGS:www.baidu.com')
}
}
task(wons,{
description('OUS')
group('xyz.wongs')
doLast {
println('WONGS:www.baidu.com')
}
})
以上这两种也是常见的写法。
- TaskContainer
任务容器,实现任务的创建操作。
tasks.create('wons',{
description('OUS')
group('xyz.wongs')
doLast {
println('WONGS:www.baidu.com')
}
})
四种处理语法,按照个人习惯熟悉其中一种即可,在 执行 gradle 命令的时候有两种做法:gradle 任务名称
、gradle:任务路径
,一般建议两者内容要求相同。
8.2. 任务属性
除了基本属性之外,还有一些继承的相关属性存在。
8.2.1. 属性设置
将分组归纳到内置的分组之中,此时可以使用 BasePlugin
常量来进行配置
全局常量
public static final String CLEAN_TASK_NAME = "clean";
public static final String ASSEMBLE_TASK_NAME = "assemble";
public static final String BUILD_GROUP = "build";
public static final String UPLOAD_ARCHIVES_TASK_NAME = "uploadArchives";
public static final String UPLOAD_GROUP = "upload";
def task = task wxy(){
doFirst {
println('[BEGIN] WONGS www.baidu.com')
}
doLast {
println('[END] WONGS www.baidu.com')
}
}
task.group(BasePlugin.BUILD_GROUP)
wxy{
description "This is My!"
}
8.2.2. 任务继承
def task = task wxy(type:Person){
description "This is My!"
// 任务禁用,任务关键性控制
enabled(true)
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] WONGS www.baidu.com')
}
doLast {
println('[END] WONGS www.baidu.com')
}
}
class Person extends DefaultTask{
@TaskAction
def doSelf(){
println('[CLAZZ] doSelf')
}
@TaskAction
def doLast(){
println('[CLAZZ] doLast')
}
}
8.2.3. 多任务依赖
task xyz(){
doFirst {
println('[xyz] WONGS xyz')
}
println('[Task] This is xyz')
doLast {
println('[xyz] WONGS xyz')
}
}
task com(dependsOn:[xyz]){
doFirst {
println('[com] WONGS com')
}
println('[Task] This is com')
doLast {
println('[com] WONGS com')
}
}
task gov(dependsOn:[com]){
doFirst {
println('[gov] WONGS gov')
}
println('[Task] This is gov')
doLast {
println('[gov] WONGS gov')
}
}
8.2.4. Onlyif
任务创建时候,可以接受一个闭包的处理,根据处理结果判断此任务是否执行。
final String BUILD_NUM = 'wongs'
def Task ot = task xyz(){
description "This is My!"
group(BasePlugin.BUILD_GROUP)
// 类似与 ebable 的形式
onlyIf {
// 执行结果
def execute = false
if (project.hasProperty('flag')){
def flag = project.property('flag')
if (BUILD_NUM==flag){
execute = true
}
}
return execute
}
doLast {
println('[END] WONGS www.baidu.com')
}
}
gradle xyz -Pflag=wongs
8.3. 多任务定义
按照定义的顺序来执行,执行顺序并不能起到前后顺序的作用。
task xyz(){
println('[Task] This is xyz')
}
task com(){
println('[Task] This is com')
}
task gov(){
println('[Task] This is gov')
}
如果父任务呈现禁用状态,那么不影响子任务的执行配置。
8.4. 深入任务定义
实际任务当中,我们还会处理存在项目的属性、方法等信息。
在整个 Gradle 项目中的信息 通过 project
得到,对应的属性使用 property()
使用,所有任务实际上都会放在 TaskContainer
进行任务管理, TaskContainer
里面保存的就是一个 Map
集合。
- 获取任务名称
def task = task (wxy){
description "This is My!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] WONGS www.baidu.com')
println('[Task Name 1] '+ wxy.name)
println('[Task Name 2] '+ project.wxy.name)
println('[Task Name 3] '+ tasks.wxy.name)
println('[Task Name 4] '+ tasks['wxy'].name)
}
doLast {
println('[END] WONGS www.baidu.com')
}
}
输入内容如下:
> Task :wxy
[BEGIN] WONGS www.baidu.com
[Task Name] wxy
[Task Name] wxy
[Task Name] wxy
[Task Name] wxy
[END] WONGS www.baidu.com
- 任务路径
路径名称和任务的名称相同。
def task = task (wxy){
description "This is My!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] WONGS www.baidu.com')
println('[Task Name 1] '+ wxy.name)
println('[Task Name 2] '+ project.wxy.name)
println('[Task Name 3] '+ tasks.wxy.name)
println('[Task Name 4] '+ tasks['wxy'].name)
println('[Task Path 1] '+ wxy.path)
println('[Task Path 2] '+ tasks.getByPath('wxy').path)
println('[Task Path 3] '+ tasks.getByPath(':wxy').path)
}
doLast {
println('[END] WONGS www.baidu.com')
}
}
> Task :wxy
[BEGIN] WONGS www.baidu.com
[Task Name 1] wxy
[Task Name 2] wxy
[Task Name 3] wxy
[Task Name 4] wxy
[Task Path 1] :wxy
[Task Path 2] :wxy
[Task Path 3] :wxy
[END] WONGS www.baidu.com
- 任务属性【重要】
执行多任务的时候如果直接使用 task
形式来创建,这种创建形式下执行将会按照顺序执行,如果此时采用如下语法定义,则可以根据执行的顺序来进行配置
def taskOne = task (taskOne){
description "This is taskOne!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] taskOne')
}
doLast {
println('[END] taskOne')
}
}
def taskTwo = task (taskTwo){
description "This is taskTwo!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] taskTwo')
}
doLast {
println('[END] taskTwo')
}
}
这样子我们可以自定义执行顺序
gradle taskTwo taskOne
> Task :taskTwo
[BEGIN] taskTwo
[END] taskTwo
> Task :taskOne
[BEGIN] taskOne
[END] taskOne
很多时候,我们需要某任务1 永远在任务2 之后执行,这种场景通过配置顺序的形式,来定义流程。
实例中我们需要使用一个新名词 mustRunAfter
def taskOne = task (taskOne){
description "This is taskOne!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] taskOne')
}
doLast {
println('[END] taskOne')
}
}
def taskTwo = task (taskTwo){
description "This is taskTwo!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] taskTwo')
}
doLast {
println('[END] taskTwo')
}
}
taskOne.mustRunAfter taskTwo
在执行命令时候我们故意让 taskOne
写在 taskTwo
前面。
gradle taskOne taskTwo
结果中我们看到 taskTwo
在 taskOne
之前被执行,这样达到自定义顺序的这样的要求。
> Task :taskTwo
[BEGIN] taskTwo
[END] taskTwo
> Task :taskOne
[BEGIN] taskOne
[END] taskOne
- 错误依赖
定义任务时候使用 mustRunAfter
,如果同时存在依赖关系,这种会进入一种递归任务执行的错误之中。
def taskOne = task (taskOne){
description "This is taskOne!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] taskOne')
}
doLast {
println('[END] taskOne')
}
}
def taskTwo = task (taskTwo){
description "This is taskTwo!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] taskTwo')
}
doLast {
println('[END] taskTwo')
}
}
taskTwo.dependsOn(taskOne)
taskOne.mustRunAfter taskTwo
gradle taskOne taskTwo
Circular dependency between the following tasks:
:taskOne
\--- :taskTwo
\--- :taskOne (*)
* Try:
- 依赖顺序
任务循环递归处理解决方式,我们换一种比较柔和的模式来完成任务顺序的处理。 这里我们用到 shouldRunAfter
。
def taskOne = task (taskOne){
description "This is taskOne!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] taskOne')
}
doLast {
println('[END] taskOne')
}
}
def taskTwo = task (taskTwo){
description "This is taskTwo!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] taskTwo')
}
doLast {
println('[END] taskTwo')
}
}
taskTwo.dependsOn(taskOne)
taskOne.shouldRunAfter taskTwo
- 任务替换/重写
按照 JAVA
概念来解释,父类中某个方法不能满足我们要求,那么子类应该考虑自身对该方法进行扩充, Gradle
中有两种重写方式
- 方式1
task build(overwrite:true){
doFirst {
println('[BEGIN] Override build')
}
}
- 方式2
def Task task = task([overwrite:true],build){
doFirst {
println('[BEGIN] Override build')
}
}
两种方式的效果是一样的,都是不再使用系统默认 build
任务,而是使用自定义的任务执行操作。
- 任务失败
def Task t1 = task (taskOne){
description "This is taskOne!"
group(BasePlugin.BUILD_GROUP)
doFirst {
if (true){
throw new StopActionException('STOP STOP')
}
}
doLast {
println('[END] taskOne')
}
}
def Task t2 = task (taskTwo){
dependsOn(taskOne)
description "This is taskTwo!"
group(BasePlugin.BUILD_GROUP)
doFirst {
println('[BEGIN] taskTwo')
}
doLast {
println('[END] taskTwo')
}
}
gradle taskOne taskTwo
> Task :taskOne
[END] taskOne
> Task :taskTwo
[BEGIN] taskTwo
[END] taskTwo
虽然第一个任务有异常抛出,但是不影响后续其他任务的执行处理。
8.5. 文件处理任务
文件操作在 Gradle
很普遍。
8.5.1. 文件定位
两种获取文件的方式,一种是 Gradle
内置,还有一种就是传统的文件获取方式。
def Task t1 = task (fileTaskOne){
group(BasePlugin.BUILD_GROUP)
doFirst {
File file = file('src/main/resource/application.properties')
println("[fileTaskOne] file "+ file)
}
}
def Task t2 = task (fileTaskTwo){
group(BasePlugin.BUILD_GROUP)
doFirst {
File file = file(new File('src'+File.separator+'main'+File.separator+'resource'+File.separator+'application.properties'))
println("[fileTaskTwo] file "+ file)
}
}
8.5.2. 资源集合
def Task t1 = task (fileTaskOne){
group(BasePlugin.BUILD_GROUP)
doFirst {
def configurableFileCollection = files('src/main/resource/application.properties','src/main/resource/spring.properties')
configurableFileCollection.each {
println(it.name)
}
}
}
8.5.3. 集合操作
通过 FileCollection
对文件获取操作,我们需要对集合进行操作。
def Task t1 = task (fileTaskCollection){
group(BasePlugin.BUILD_GROUP)
doFirst {
def configurableFileCollection = files('src/main/resource/application.properties','src/main/resource/spring.properties')
// 文件集合的相加
def union = configurableFileCollection+ files('src/main/resource/redis.properties')
union.each {
println(it.name)
}
println('*' * 40)
// 文件集合的相减
def dif = configurableFileCollection-files('src/main/resource/application.properties')
dif.each {
println(it.name)
}
println('*' * 40)
println('[相加后的集合] ' +union.size())
println('[相减后的集合] ' +dif.size())
}
}
8.5.4. 文件列表
def Task t1 = task (fileTaskList){
group(BasePlugin.BUILD_GROUP)
doFirst {
File file = file('src/main/resources')
def fileCollection = files(file.listFiles())
fileCollection.each {
println(it)
}
}
}
8.5.5. 文件树
def Task t1 = task (fileTaskTree){
group(BasePlugin.BUILD_GROUP)
doFirst {
def fileTree = fileTree('src')
fileTree.exclude('**/*.java','**/java/','**/java/')
fileTree.include('**/*.properties','**/*.yml')
fileTree.visit {
println(it)
}
}
}
8.5.6. 源目录文件
sourceSets {
main{
java{
srcDirs('src/main/java')
}
resources {
srcDirs('src/main/resources','src/main/config')
}
}
}
def Task t1 = task (fileTaskSource){
group(BasePlugin.BUILD_GROUP)
doFirst {
sourceSets.main.allJava.each {
println(it)
}
println('***' * 50)
sourceSets.main.resources.each {
println(it)
}
}
}
8.5.7. 文件拷贝
def Task t1 = task (fileTaskCopy,type:Copy){
from('src/main/resources')
from('src/main/config')
from('src/main/java')
into('build/out')
include('**/*.xml')
include('**/*.yml')
exclude('**/*.java')
}
9. 依赖管理
9.1. 创建可执行Jar文件
配置项
plugins {
id 'java'
}
group 'xyz.wongs'
version '1.0-SNAPSHOT'
def jdkVersion = 1.8
def CHARSET = 'UTF-8'
// 源代码版本
sourceCompatibility = jdkVersion
targetCompatibility = jdkVersion
// 主程序
def MainClassName = 'xyz.wongs.drunkard.WarApplication'
jar {
// 生成文件名,不指定,则使用项目名称
archivesBaseName = 'war3'
// 设置文件编码
manifestContentCharset = CHARSET
// 设置元数据编码
metadataCharset = CHARSET
manifest {
// 程序版本号
attributes 'Manifest-Version': getArchiveVersion().getOrNull(),
// 程序主类
'Main-Class': "$MainClassName",
//
'Implementation-Title': 'War3-Gradle',
//版本编号
'Implementation-Version': archiveVersion
}
// 第三方组件包配置到lib目录
into('lib') {
// 运行时的组件
from configurations.runtime
}
}
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.0'
compile group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '2.3.3'
compile group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
compile group: 'com.alibaba', name: 'druid', version: '1.2.4'
}
build clean build
在 build/libs
文件夹中 war3-1.0-SNAPSHOT.jar
打包的文件,这是一个可执行文件
9.2. 依赖库打包范围
打包范围
打包范围 | 描述 |
---|---|
compile |
依赖的库文件在编译和运行都需要,前提: plugins {id 'java'} 和 plugins {id 'war'} |
providedCompile |
在编译需要,前提: plugins {id 'war'} |
runtime |
运行时需要,编译时不需要,前提: plugins {id 'java'} |
testCompile |
测试时候需要 |
debugCompile |
Debug模式下需要 |
releaseCompile |
依赖文件在release模式下生效 |
implementation |
9.2.1. 本地jar
在默认情况下所有项目中需要使用到的Gradle依赖全部都是通过网络进行下载的, 但是如果说现在某些依赖己经在本地了, 不希望再去通过网络引用 , 那么这一点在Gradle中也是可以的.
dependencies {
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.0'
compile group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '2.3.3'
compile group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
compile group: 'com.alibaba', name: 'druid', version: '1.2.4'
comile fileTree(dir: 'libs',includes: ['*.jar'])
}
- 第一步. 在项目中添加一个新的目录
libs
; - 第二步:将本地需要导入的
jar
文件保存在此目录之中; - 第三步:修改
build.gradle
配置文件, 在依赖配置上进行本地的引用;
9.2.2. compile替换
在进行Gradle依 赖处理的时候最为常用的肯定是 compile
, 但是如果现在要想将其更换为 api
, 则需要在项目中引入—些新的插件。
plugins {
id 'java'
id 'java-library'
}
group 'xyz.wongs'
version '1.0-SNAPSHOT'
def jdkVersion = 1.8
def CHARSET = 'UTF-8'
// 源代码版本
sourceCompatibility = jdkVersion
targetCompatibility = jdkVersion
// 主程序
def MainClassName = 'xyz.wongs.drunkard.WarApplication'
jar {
// 生成文件名,不指定,则使用项目名称
archivesBaseName = 'war3'
// 设置文件编码
manifestContentCharset = CHARSET
// 设置元数据编码
metadataCharset = CHARSET
manifest {
// 程序版本号
attributes 'Manifest-Version': getArchiveVersion().getOrNull(),
// 程序主类
'Main-Class': "$MainClassName",
//
'Implementation-Title': 'War3-Gradle',
//版本编号
'Implementation-Version': archiveVersion
}
// 第三方组件包配置到lib目录
into('lib') {
// 运行时的组件
from configurations.runtime
}
}
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.0'
compile group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '2.3.3'
compile group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
compile fileTree(dir:'libs', includes: ['*.jar'])
api 'com.alibaba:druid:1.2.4'
}
使用 api
的处理方式进行打包 的时候, 会发现无法将依赖库生成到最终生成的打包文件之中, 所以如果非必须的时候依然还是建议使用 compile
操作。
9.2.3. 查看依赖信息
gradle -q dependencies
15:21:51: Executing task 'dependencies --quiet'...
------------------------------------------------------------
Project :gradle-war3
------------------------------------------------------------
annotationProcessor - Annotation processors and their dependencies for source set 'main'.
No dependencies
api - API dependencies for source set 'main'. (n)
\--- com.alibaba:druid:1.2.4 (n)
apiElements - API elements for main. (n)
No dependencies
archives - Configuration for archive artifacts. (n)
No dependencies
compileClasspath - Compile classpath for source set 'main'.
+--- com.alibaba:druid:1.2.4
+--- javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
\--- javax.servlet:javax.servlet-api:4.0.1
compileOnly - Compile only dependencies for source set 'main'. (n)
No dependencies
default - Configuration for default artifacts. (n)
No dependencies
implementation - Implementation only dependencies for source set 'main'. (n)
No dependencies
runtimeClasspath - Runtime classpath of source set 'main'.
+--- com.alibaba:druid:1.2.4
+--- javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
\--- javax.servlet:javax.servlet-api:4.0.1
runtimeElements - Elements of runtime for main. (n)
No dependencies
runtimeOnly - Runtime only dependencies for source set 'main'. (n)
No dependencies
testAnnotationProcessor - Annotation processors and their dependencies for source set 'test'.
No dependencies
testCompileClasspath - Compile classpath for source set 'test'.
+--- com.alibaba:druid:1.2.4
+--- javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+--- javax.servlet:javax.servlet-api:4.0.1
\--- org.junit.jupiter:junit-jupiter-api:5.7.0
+--- org.junit:junit-bom:5.7.0
| +--- org.junit.jupiter:junit-jupiter-api:5.7.0 (c)
| \--- org.junit.platform:junit-platform-commons:1.7.0 (c)
+--- org.apiguardian:apiguardian-api:1.1.0
+--- org.opentest4j:opentest4j:1.2.0
\--- org.junit.platform:junit-platform-commons:1.7.0
+--- org.junit:junit-bom:5.7.0 (*)
\--- org.apiguardian:apiguardian-api:1.1.0
testCompileOnly - Compile only dependencies for source set 'test'. (n)
No dependencies
testImplementation - Implementation only dependencies for source set 'test'. (n)
No dependencies
testRuntimeClasspath - Runtime classpath of source set 'test'.
+--- com.alibaba:druid:1.2.4
+--- javax.servlet.jsp:javax.servlet.jsp-api:2.3.3
+--- javax.servlet:javax.servlet-api:4.0.1
\--- org.junit.jupiter:junit-jupiter-api:5.7.0
+--- org.junit:junit-bom:5.7.0
| +--- org.junit.jupiter:junit-jupiter-api:5.7.0 (c)
| \--- org.junit.platform:junit-platform-commons:1.7.0 (c)
+--- org.apiguardian:apiguardian-api:1.1.0
+--- org.opentest4j:opentest4j:1.2.0
\--- org.junit.platform:junit-platform-commons:1.7.0
+--- org.junit:junit-bom:5.7.0 (*)
\--- org.apiguardian:apiguardian-api:1.1.0
testRuntimeOnly - Runtime only dependencies for source set 'test'. (n)
No dependencies
(c) - dependency constraint
(*) - dependencies omitted (listed previously)
(n) - Not resolved (configuration is not meant to be resolved)
A web-based, searchable dependency report is available by adding the --scan option.
15:21:52: Task execution finished 'dependencies --quiet'.
9.2.4. 依赖过滤
有些时候可能并不需要将所有范围的依赖全部进行列出, 只希望列出 Compile
依赖范围所以也可以在依赖列表的时候进行一些参数的配置。
gradle -q dependencies --configuration compile
15:24:51: Executing tasks 'dependencies --configuration compile --quiet'...
------------------------------------------------------------
Project :gradle-war3
------------------------------------------------------------
compile - Dependencies for source set 'main' (deprecated, use 'implementation' instead). (n)
+--- javax.servlet.jsp:javax.servlet.jsp-api:2.3.3 (n)
+--- javax.servlet:javax.servlet-api:4.0.1 (n)
\--- unspecified (n)
(n) - Not resolved (configuration is not meant to be resolved)
A web-based, searchable dependency report is available by adding the --scan option.
15:24:51: Tasks execution finished 'dependencies --configuration compile --quiet'.
9.2.5. 依赖查找
一个项目中有可能会存在有大扭的依赖, 那么也可以直接利用 gradle 项目进行指定依赖名称查找。
范例:查找项目中是否存在有 druid
依赖。
gradle -q dependencyInsight --dependency druid --configuration compile
15:28:18: Executing tasks 'dependencyInsight --dependency druid --configuration compile --quiet'...
com.alibaba:druid:1.2.4
variant "runtime" [
org.gradle.status = release (not requested)
org.gradle.usage = java-runtime (not requested)
org.gradle.libraryelements = jar (not requested)
org.gradle.category = library (not requested)
]
com.alibaba:druid:1.2.4
\--- compile
A web-based, searchable dependency report is available by adding the --scan option.
15:28:18: Tasks execution finished 'dependencyInsight --dependency druid --configuration compile --quiet'.
范例:查找项目中是否存在有 spring
gradle -q dependencyInsight --dependency spring --configuration compile
15:29:28: Executing tasks 'dependencyInsight --dependency spring --configuration compile --quiet'...
No dependencies matching given input were found in configuration ':gradle-war3:compile'
15:29:29: Tasks execution finished 'dependencyInsight --dependency spring --configuration compile --quiet'.
9.3. 依赖库排除
在进行依赖库引入的时候, 由千各个不同的依赖库有可能去引用同— 个依赖文件(日志), 这样就会造成各种的包引入不明确的问题, 所以就需要进行一些依赖的排除操作。
- 日志依赖
修改 build.gradle
配置文件, 进行一些日志依赖文件的定义。
dependencies {
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.0'
compile group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '2.3.3'
compile group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
compile fileTree(dir:'libs', includes: ['*.jar'])
compile group: 'com.alibaba', name: 'druid', version: '1.2.4'
compile group: 'org.slf4j', name: 'slf4j-api', version: '1. 7. 30'
compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1. 7. 30'
compile group: 'org.slf4j', name: 'log4j-over-slf4j', version: '1. 7. 30'
compile group: 'org.slf4j', name: 'slf4j-nop',version: '1. 7. 30'
compile group: 'org. apache. logging. log4j', name: 'log4j-api',version: '2.13.2'
compile group: 'org. apache. logging. log4j', name: 'log4j-to-sl f4j',version: '2.13.2'
}
- 日志文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<substitutionProperty name="log.base" value="d:/data/log"/>
<!-- 控制台输出日志 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%msg%n</pattern>
</layout>
</appender>
<appender name="infoFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<File>${log.base}.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.base}.%d{yyyyMMdd}.log.zip</FileNamePattern>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) [%thread] %cyan(%logger) - %msg%n</pattern>
</layout>
</appender>
<appender name="errorFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!--<Encoding>UTF-8</Encoding>-->
<File>${log.base}-error.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${log.base}-error.%d{yyyyMMdd}.log.zip</FileNamePattern>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) [%thread] %cyan(%logger) - %msg%n</pattern>
</layout>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="infoFile" />
</root>
<root level="ERROR">
<appender-ref ref="errorFile" />
</root>
</configuration>
- 代码编写
package xyz.wongs.drunkard;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author WCNGS@QQ.COM
* @ClassName ResultCode 定义的接口状态码
* @Description
* @Github <a>https://github.com/rothschil</a>
* @date 2020/12/24 14:36
* @Version 1.0.0
*/
public class WarApplication {
private static final Logger LOGGER= LoggerFactory.getLogger(WarApplication.class);
public static void main(String[] args) {
LOGGER.info("=========");
System.out.println("Welcome Gradle World");
LOGGER.info("=========");
}
}
执行结果
Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar AND bound slf4j-log4j12.jar on the class path, preempting StackOverflowError. See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.
这时候出现依赖重复的问题,问题的解决方式有三种:
9.3.1. 依赖排除【推荐】
需要进行依赖的排除处理 修改 build.gradle
配置文件
configurations {
all*.exclude group: 'org.slf4j', module:'slf4j-log4j12'
}
引入了全局的排除设置,样就表示在进行依赖引入的时候不在项目里面去使用 org.slf4j: slf4j-log4j12
9.3.2. 模块排除
可以针对于个别模块进行排除,
configurations {
// 1、 全局排除
//all*.exclude group: 'org.slf4j', module:'slf4j-log4j12'
// 2、模块排除
compile.exclude module:'slf4j-log4j12'
}
9.3.3. 依赖排除
可以直接在进行某个依赖配置的时候排除。
compile ('org.slf4j:slf4j-log4j12:1.7.30'){
exclude module:'log4j-api'
}
9.4. 依赖库版本库号统一管理
项目中新建一个文件 config.gradle
,编写内容如下:
ext{
jdkVersion = JavaVersion.VERSION_11
druidVersion = '1.2.4'
}
将 config.gradle
文件引入 build.gradle
中
plugins {
id 'java'
}
apply from : 'config.gradle'
group 'xyz.wongs'
version '1.0-SNAPSHOT'
def CHARSET = 'UTF-8'
// 源代码版本
sourceCompatibility = jdkVersion
targetCompatibility = jdkVersion
// 主程序
def MainClassName = 'xyz.wongs.drunkard.WarApplication'
jar {
// 生成文件名,不指定,则使用项目名称
archivesBaseName = 'war3'
// 设置文件编码
manifestContentCharset = CHARSET
// 设置元数据编码
metadataCharset = CHARSET
manifest {
// 程序版本号
attributes 'Manifest-Version': getArchiveVersion().getOrNull(),
// 程序主类
'Main-Class': "$MainClassName",
//
'Implementation-Title': 'War3-Gradle',
//版本编号
'Implementation-Version': archiveVersion
}
// 第三方组件包配置到lib目录
into('lib') {
// 运行时的组件
from configurations.runtime
}
}
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.0'
compile group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '2.3.3'
compile group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
compile fileTree(dir:'libs', includes: ['*.jar'])
compile group: 'com.alibaba', name: 'druid', version: druidVersion
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.30'
compile group: 'org.slf4j', name: 'log4j-over-slf4j', version: '1.7.30'
compile group: 'org.slf4j', name: 'slf4j-nop',version: '1.7.30'
compile group: 'org.apache.logging.log4j', name: 'log4j-api',version: '2.13.2'
compile group: 'org.apache.logging.log4j', name: 'log4j-to-slf4j',version: '2.13.2'
compile ('org.slf4j:slf4j-log4j12:1.7.30'){
exclude module:'log4j-api'
}
}
configurations {
// 1、 全局排除
//all*.exclude group: 'org.slf4j', module:'slf4j-log4j12'
// 2、模块排除
//compile.exclude module:'slf4j-log4j12'
}
其中 apply from : 'config.gradle'
以及 compile group: 'com.alibaba', name: 'druid', version: druidVersion
为变动的。
JDK版本 | major.minor.version |
---|---|
1.1 | 45 |
1.2 | 46 |
1.3 | 47 |
1.4 | 48 |
1.5 | 49 |
1.6 | 50 |
1.7 | 51 |
1.8 | 52 |
命令行进入程序 class
文件路径 执行:
javap -verbose WarApplication.class
9.5. 依赖库集中管理
虽然可以通过单独配置文件模式将所有需要的版本号进行统— 的配置, 但是从某些严格意义上来讲, 如果将所有的依赖都配
置在 build.gradle
文件里面, 那么这个文件的长度就实在太可怕了(回想一下, 传统 Maven
项目之中的配置文件的长度)。
在 Gradle
中考虑到了传统 Maven
工具所带来的各种的维护问题, 所以对于依赖库的管理最佳的实现模式是建立有一个单独的依赖配置文件, 通过这个依赖配置文件定义所有要使用的依赖, 随后在 build.gradle
文件里面去通过这个依赖文件引入相应的依赖库 ( build.gradle
中不直接参与任何版本的操作)。
- 【依赖文件】在项目中定义有一个
dependencies.gradle
配置文件; - 【编辑文件】修改
dependencies.gradle
文件 , 将所有的依赖库以及对应的版本进行有效定义;
ext.versions = [
junitVersion:'5.7.0',
javaxServletJspApi : '2.3.3',
javaxServletApi:'4.0.1',
druidVersion:'1.2.4',
slf4jApi:'1.7.30',
apacheLog4j:'2.13.2'
]
ext.libraries = [
'junit-jupiter-api':"org.junit.jupiter:junit-jupiter-api:${versions.junitVersion}",
'javax.servlet.jsp-api':"javax.servlet.jsp:javax.servlet.jsp-api:${versions.javaxServletJspApi}",
'javax.servlet-api':"javax.servlet:javax.servlet-api:${versions.javaxServletApi}",
'druid' :"com.alibaba:druid:${versions.druidVersion}",
'slf4j-api':"org.slf4j:slf4j-api:${versions.slf4jApi}",
'log4j-over-slf4j':"org.slf4j:log4j-over-slf4j:${versions.slf4jApi}",
'slf4j-nop':"org.slf4j:slf4j-nop:${versions.slf4jApi}",
'log4j-api':"org.apache.logging.log4j:log4j-api:${versions.apacheLog4j}",
'log4j-to-slf4j':"org.apache.logging.log4j:log4j-to-slf4j:${versions.apacheLog4j}"
]
修改 build.gradle
文件 , 引入以上的依赖库文件 apply from : 'dependencies.gradle'
。
plugins {
id 'java'
}
apply from : 'config.gradle'
apply from : 'dependencies.gradle'
group 'xyz.wongs'
version '1.0-SNAPSHOT'
def CHARSET = 'UTF-8'
// 源代码版本
sourceCompatibility = jdkVersion
targetCompatibility = jdkVersion
// 主程序
def MainClassName = 'xyz.wongs.drunkard.WarApplication'
jar {
// 生成文件名,不指定,则使用项目名称
archivesBaseName = 'war3'
// 设置文件编码
manifestContentCharset = CHARSET
// 设置元数据编码
metadataCharset = CHARSET
manifest {
// 程序版本号
attributes 'Manifest-Version': getArchiveVersion().getOrNull(),
// 程序主类
'Main-Class': "$MainClassName",
//
'Implementation-Title': 'War3-Gradle',
//版本编号
'Implementation-Version': archiveVersion
}
// 第三方组件包配置到lib目录
into('lib') {
// 运行时的组件
from configurations.runtime
}
}
repositories {
mavenCentral()
}
dependencies {
testCompile(
libraries.'junit-jupiter-api'
)
compile(
libraries.'javax.servlet.jsp-api',
libraries.'javax.servlet-api',
libraries.'druid',
libraries.'slf4j-api',
libraries.'log4j-over-slf4j',
libraries.'slf4j-nop',
libraries.'log4j-api',
libraries.'log4j-to-slf4j'
)
compile fileTree(dir:'libs', includes: ['*.jar'])
compile ('org.slf4j:slf4j-log4j12:1.7.30'){
exclude module:'log4j-api'
}
}
configurations {
// 1、 全局排除
//all*.exclude group: 'org.slf4j', module:'slf4j-log4j12'
// 2、模块排除
//compile.exclude module:'slf4j-log4j12'
}
那么此时的Gradle项目就可以通过一个专屈的依赖文件进行所有的依赖库的管理了, 以后如果要维护版本只需要修改专属的依赖配置文件即可(不需要改动 build.gradle
文件)。
10. build.gradle配置
10.1. 日志信息
- 日志级别
LEVEL | 用途 |
---|---|
ERROR | 错误信息 |
QUIET | 重要消息 |
WARN | 警告信息 |
LIFECYCKE | 进度消息 |
INFO | 一般信息消息 |
DEBUG | 调试信息 |
task(infoTask){
doFirst {
logger.error('[error msg]')
logger.quiet('[quiet msg]')
logger.warn('[warn msg]')
logger.lifecycle('[lifecycle msg]')
logger.info('[info msg]')
logger.debug('[debug msg]')
}
}
- 日志控制
对千不同级别的日志需要通过任务执行的时候配置不同的日志等级才可以实现输出, 对于日志等级有如下的几个配置项。
选项 | 级别 |
---|---|
默认选项 | lifecycle+ |
-q or -quiet | quiet+ |
-w or -warn | warn+ |
-i or -info | info+ |
-d or -debug | debug+ |
命令行执行
gradle infoTask -d
10.2. 源代码打包
对千任何—个项目来讲, 除了需要将核心的功能程序(编译后的)进行打包处理之外, 实际上还需要考虑的就是开源项目中的源代码的打包操作, 对千源代码的打包操作, 需要单独配暨有一个 Gradle
任务才可以实现。
- 打包操纵
task(sourceTask,type:Jar){
// 1、生成 JAR名称
baseName 'wongs'
// 2、打包的版本
version '1.0.0'
// 3、文件的后缀类型
classifier 'sources'
// 4、源码读取路径
from sourceSets.main.allSource
//
exclude('**/*.xml','**/*.properties')
// 5、目标存储路径
destinationDir file("$buildDir/source-jar")
manifest {
attributes 'packageName': 'yootk-sources',
'Built-By': 'Wongs-Gradle',
'Built-date': new Date().format('yyyy-MM-dd HH:mm:ss'), 'Manifest-Version': archiveVersion
}
}
gradle sourceTask
- 打包时间
当前的操作虽然可以编写任务实现源代码的打包处理操作, 可是有一个问题, 一般的做法是在程序最终编译的时候才进行的打包处理 , 如果按照以上的方式单独定义一个新的任务, 则意味着就需要在整个的程序之中就要单独配置任务, 能否将这些任务合并在一起呢?如果要想实现这样的方式实际上就是任务的依赖关系。
task sourceTask(type:Jar,dependsOn: classes){
archiveClassifier = 'sources'
from sourceSets.main.allSource
}
以上的任务仅仅是对已有的任务做了一个扩展, 但是需要注意的是, 毕竟现在的需求是将整个的源代码的打包操作放在 build 之中所以还需要进行一个额外的配置。
// 打包的操作任务
artifacts {
archives(sourceTask)
}
在源代码打包的过程之中, 如果不希望单独定义一个新的任务, 就和已有任务整合在一起 , 但是所有的新任务一定要在 artifacts
之中进行配置, 否则这些任务将无法正常执行。
10.3. 打包JavaDoc
—个完善的项目在进行打包的时候—般会认为三个 *jar
文件 主程序 (xx-xxx.jar
) 、 源代码 (xx-xxx-sources.jar
) 、 文档 (xx-xxx-javadoc.Jar
) , 如果要想将程序生成 javadoc
文档, 那么首先一定需要在项目中追加相应的文 档说明, 同时还需要在 build.gradle
文件里面定义有相关的任务处理。
- html网页
task javadocTask(type :Javadoc){
// 定义所有JAVA代码
source= sourceSets.main.allJava
}
// 文档编码
tasks.withType(Javadoc){
options.encoding("UTF-8")
}
gradle javadocTask
- jar文件
最终在进行项目发布的时候肯定要生成 javadoc
的 jar
文件, 所以此时就需要定义有一个打包任务。
在 HTML
生威 javadoc
才可以打包
plugins {
id 'java'
}
group 'xyz.wongs'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
task sourceTask(type:Jar,dependsOn: classes){
archiveClassifier = 'sources'
from sourceSets.main.allSource
}
task javadocTask(type :Javadoc){
// 定义所有JAVA代码
source = sourceSets.main.allJava
}
task javadocJarTask(type :Jar,dependsOn: javadocTask){
archiveClassifier = 'javadoc'
from javadocTask.destinationDir
}
// 打包的操作任务
artifacts {
archives(sourceTask)
archives(javadocJarTask)
}
dependencies {
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.0'
testCompile group: 'org.junit.vintage', name: 'junit-vintage-engine', version: '5.7.0'
testCompile group: 'org.junit.platform', name: 'junit-platform-launcher', version: '1.7.0'
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.7.0'
}
// 文档编码
tasks.withType(Javadoc){
options.encoding("UTF-8")
//
options.addStringOption('Xdoclint:none', '-quiet')
options.addStringOption('encoding', 'UTF-8')
}
// 程序编译
tasks.withType(JavaCompile){
options.encoding("UTF-8")
}
test{
useJUnitPlatform()
}
task(infoTask){
doFirst {
logger.error('[error msg]')
logger.quiet('[quiet msg]')
logger.warn('[warn msg]')
logger.lifecycle('[lifecycle msg]')
logger.info('[info msg]')
logger.debug('[debug msg]')
}
}
执行命令
gradle clean build -x test
10.4. 程序测试控制
在 Gradle
项目中所有的代码肯定都要有相应的测试用例存在, 但是如果说在— 些环境下测试用例可能无法正常执行, 那么面对千这样的情况, 就需要在每次编译打包的时候都使用 -x test
来跨过测试, 但是在 Maven
里面有一种插件, 通过配置可以避免执行测试的代码, 但是在 Gradle 中可没有这样的配置插件, 所以如果要想实现代码测试的跨过, 就需要手工编写程序。
package xyz.wongs.drunkard.msg;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import xyz.wongs.drunkard.msg.impl.IntfMessageImpl;
public class IntfMsgTest {
@Test
public void testMsg() {
IntfMessage intfMessage = new IntfMessageImpl();
Assertions.assertEquals(intfMessage.getMsg(null), "Love Java");
}
}
以上代码在执行过程中,会执行不通过,因为 intfMessage.getMsg(null)
返回内容与 Love Java
不相同,结果如下:
expected: <I Love Java> but was: <Love Java>
Expected :I Love Java
Actual :Love Java
类似这样的测试不成功,我们之前的做法都是通过 -x test
来忽略,但是这样做有些麻烦,这里推荐大家使用编程方式来解决,思路就是做个开关。
在 build.gradle
添加任务。
// 所有操作准备好触发该任务
gradle.taskGraph.whenReady {
tasks.each {
if (it.getName().contains('test')){
it.enabled(false)
}
}
}
当你的项目中配备了这样的处理之后, 实际上连最终的所有的程序的测试都完全失效了, 因为只要发现是测试的指令, 全部都关闭任务处理了。
10.5. 多环境配置管理
项目如果要想正常使用,则一般会经历· 开发环境(dev
)、测试环境(beta/test
)、生产环境(dev
),不同的环境对千—些程序的配置信息也一定会有不同, 那么这样的操作就都可以通过 profile
来进行配置, 按照正常的开发, 应该将所有的网络服务器的信息,保存在不同的 profile
文件里面, 例如, 现在假设在 src/main
目录下创建有一个 profile
公共目录。
我这里为了演示创建一个 profiles
目录,别忘了需要将他设置为 Resource Root
。
// 测试环境
profiles\beta\config\db.properties
// 开发环境
profiles\dev\config\db.properties
// 生产环境
profiles\prod\config\db.properties
以上文件的内容以 KEY-VALUE
形式存在,其中 Key
必须一样。
然后我们设置 build.gradle
内容:我们需要对它 添加环境变量的定义;对源代码选项进行动态设置。
def env = System.getProperty('env')
sourceSets {
main{
java{
srcDirs('src/main/java')
}
resources {
srcDirs('src/main/resources',"src/main/profiles/${env}")
}
}
}
执行 gradle build -Denv=beta
操作,其中 -Denv=beta
是我们指定的环境信息。
开始检查 config\db.properties
内容,是否为我们指定环境信息。
长期依赖如果使用 Maven 都会发现有一个核心的问题. 依赖库的版本永远都是需要固定配置, 即便有不同的 profile
, 那么依赖库也是无法变更的, 但是在 Gradle
里面 , 将这—问题解决了 , 在之前为了进行所有依赖的统一管理, 提供有 一个 dependencies.gradle
配置文件, 那么如果要想实现不同版本的切换, 就可以通过这样的文件形式来进行控制, 下面构建三个不同的 dependencies-xxx.gradle
文件, 其中代表着不同的配置环境,再通过环境变量信息动态引入。
文件列表如下:
|---gradle/
|---|---build.gradle
|---|---config.gradle
|---|---dependencies-beta.gradle ---1.1.17
|---|---dependencies-dev.gradle ---1.1.11
|---|---dependencies-prod.gradle ---1.2.4
为了演示效果,我们针对三个文件中 druidVersion:'XX'
中的版本号设置不一样。
ext.versions = [
junitVersion:'5.7.0',
javaxServletJspApi : '2.3.3',
javaxServletApi:'4.0.1',
druidVersion:'xxx',
slf4jApi:'1.7.30',
apacheLog4j:'2.13.2'
]
ext.libraries = [
'junit-jupiter-api':"org.junit.jupiter:junit-jupiter-api:${versions.junitVersion}",
'javax.servlet.jsp-api':"javax.servlet.jsp:javax.servlet.jsp-api:${versions.javaxServletJspApi}",
'javax.servlet-api':"javax.servlet:javax.servlet-api:${versions.javaxServletApi}",
'druid' :"com.alibaba:druid:${versions.druidVersion}",
'slf4j-api':"org.slf4j:slf4j-api:${versions.slf4jApi}",
'log4j-over-slf4j':"org.slf4j:log4j-over-slf4j:${versions.slf4jApi}",
'slf4j-nop':"org.slf4j:slf4j-nop:${versions.slf4jApi}",
'log4j-api':"org.apache.logging.log4j:log4j-api:${versions.apacheLog4j}",
'log4j-to-slf4j':"org.apache.logging.log4j:log4j-to-slf4j:${versions.apacheLog4j}"
]
在 build.gradle
文件中动态引入, apply from : "dependencies-${env}.gradle"
,这时候我们执行打包操作 gradle build -Denv=dev
。
基于这种配置文件编程的构建工具,在整体的使用上就会非常的灵活,各种可能你所需要功能都可以利用编程来完成。
11. 父项目配置
实际上所谓的多项目指的就是 父子项目
, 在实际项目开发中, 任何— 个庞大的项目为了方便管理肯定会拆分为若干个不同的子模块, 而后每一个子模块可以单独实现某些功能, 例如:有一个公共的组件模块、 业务模块、 WEB前端模块, 这些子模块需要进行一些特定依赖的使用, 如果现在分别创建这些 Gradle
项目, 则会造成如下的问题
Gradle
中一定要进行大丞的结构配置- 需要引入大量的第三方依赖库
- 还需要考虑到一些任务的配置(
Junits
编码问题)
如果现在要想进行项目开发, 则一定要将所有的依赖以及公共的任务放在公共的父项目之中, 随后子模块可以继承这些配置。