依赖的 Scope
- compile
- runtime
- compileOnly (新版才支持)
- testCompile
- testRuntime
项目依赖关系
gradle dep
gradle dependencies
依赖 Maven 仓库
compile 'groupId:artifactId:version'
依赖其他子项目
compile project(':dependency-project')
依赖本地 jar 包
compile files('spring-core.jar', 'spring-aop.jar')
compile fileTree(dir: 'src/main/webapp/WEB-INF/lib', include: '*.jar')
dir 可以是绝对路径,也可以是相对于工程目录的项目路径
打包工程
gradle assemble // 编译,打包
gradle build // 编译,执行测试,打包
定制包名
打包时制定包名,例如默认打包出来是 Exam.war,而我们需要的是 Exam.zip
war.archiveName 'Exam.zip'
编译工程
gradle compileJava
指定编译的输出目录
buildDir = new File(rootProject.projectDir, '../build/' + project.name)
指定 Maven 仓库
allprojects {
repositories {
mavenLocal()
mavenCentral()
maven{ url 'http://maven.edu-edu.com.cn/content/groups/public/' }
// 带认证的库
maven {
url 'http://maven.edu-edu.com.cn/content/groups/public/'
credentials {
username 'admin'
password '*****'
}
}
}
}
上传 jar 包到 Maven 仓库
- 命令: gradle uploadArchives
- Release 版本地址: maven.edu-edu.com.cn/nexus/conte…
- Snapshop 版本地址: maven.edu-edu.com.cn/nexus/conte…
- 上传的地址和下载的地址是有区别的
uploadArchives {
repositories {
mavenDeployer {
repository(url: "http://maven.edu-edu.com.cn/nexus/content/repositories/releases/") {
authentication(userName: "admin", password: "*****")
}
// 以下三项可选
pom.groupId = "$project.group"
pom.artifactId = "$artifactId" // 默认为项目的目录名
pom.version = "$project.version"
}
}
}
排除冲突的 jar 包
例如 dubbo 2.5 依赖 Spring 2,现在基本都用 Spring 4,所以需要把 dubbo 依赖的 Spring 2 的依赖去掉,使用 exclude:
compile('com.alibaba:dubbo:2.5.3') {
exclude group: 'org.springframework', module: 'spring'
}
打包时过滤掉不需要的 jar 包
war {
// 打包时只包含以下几个 jar 包
classpath = classpath.filter { file ->
file.name.startsWith('lms-client') ||
file.name.startsWith('dict-client') ||
file.name.startsWith('e-platform-client')
}
}
打包时替换 META-INF/context.xml 中的占位符
war {
// gradle build 打包时替换 META-INF 下的文件
from("$webAppDir/META-INF") {
eachFile {
it.filter(ReplaceTokens, tokens: loadConfiguration())
}
into('META-INF')
}
}
运行时替换 META-INF/context.xml 中的占位符
任务 prepareInplaceWebApp 执行完后执行自定义任务,例如替换 context.xml 中的占位符
project.afterEvaluate {
// prepareInplaceWebApp 的时候替换 META-INF 下的文件,例如生成 context.xml
tasks.getByPath('prepareInplaceWebApp').doLast {
copy {
from("$webAppDir/META-INF") {
eachFile {
it.filter(ReplaceTokens, tokens: loadConfiguration())
}
}
into("$buildDir/inplaceWebapp/META-INF")
}
}
}
获取命令中的参数
推荐使用 -D 的方式
命令: gradle -Denv=development clean assemble
获取: def environment = System.getProperty('env', 'development')
命令: gradle -Penv=develop clean assemble
获取: def environment = hasProperty('env') ? env : 'development'
资源文件内容动态替换
def loadConfiguration() {
// 获取 gradle 参数中 -Penv 的值: gradle -Penv=development clean assemble
def environment = hasProperty('env') ? env : 'development'
def configFile = file('config.groovy') // 配置文件
return new ConfigSlurper(environment).parse(configFile.toURI().toURL()).toProperties()
}
processResources {
// src/main/resources 下的文件中 @key@ 的内容使用 config.groovy 里对应的进行替换
from(sourceSets.main.resources.srcDirs) {
filter(ReplaceTokens, tokens: loadConfiguration())
}
}
// config.groovy 的内容
environments {
development {
db {
host = '127.0.0.1'
username = 'root'
password = 'root'
database = 'db_exam'
}
}
production {
db {
host = '192.168.10.123'
username = 'root'
password = 'sluper'
database = 'db_exam'
}
}
}
使用嵌入式服务器 Tomcat
apply plugin: 'org.akhikhl.gretty'
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.akhikhl.gretty:gretty:1.4.0'
}
}
gretty {
port = 8080
contextPath = ''
servletContainer = 'tomcat7'
}
// gretty 的更多配置
gretty {
httpPort = 8080
debugPort = httpPort + 1
servicePort = httpPort + 2
statusPort = httpPort + 3
httpsPort = httpPort + 4
httpsEnabled = true
contextPath = ''
jvmArgs = ['-Xmx1024M', '-XX:PermSize=128M', '-XX:MaxPermSize=256M']
servletContainer = 'jetty7'
scanInterval = 0
inplaceMode = 'hard'
debugSuspend = false
enableNaming = true // 启用 JNDI
managedClassReload = true
}
Tomcat 的 GET 请求的默认编码是 ISO8859-1,如果 GET 需要使用 UTF-8 的话,需要在
server.xml中设置URIEncoding为 UTF-8:<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>在 Gretty 中没有提供设置
URIEncoding的选项,但是可以设置serverConfigFile引用 Tomcat 的server.xml来达到目的,例如:gretty { httpPort = 8080 contextPath = '' servletContainer = 'tomcat7' serverConfigFile = "server.xml" inplaceMode = 'hard' debugSuspend = false managedClassReload = true recompileOnSourceChange = false }
Gretty 热部署优化
Gretty 热部署的相关配置,下面几项都默认设置为 true (reload 表示重新加载整个 web 应用):
recompileOnSourceChange// Java 文件变化后自动编译reloadOnClassChange// Class 文件变化后 reloadreloadOnConfigChange// 配置文件如 web.xml 变化后 reloadreloadOnLibChange// lib 目录下的 jar 变化后 reload例如 Java 文件修改保存后会自动编译,导致 Class 文件变化,然后 gretty 会重新加载整个 Web 应用,例如应用启动时要执行计划任务,检查数据库的结构等,这样的热部署效率太低。
如果 Class 文件变化后,能不能只加载 Class 文件,而不是重新加载整个 Web 应用呢?设置
managedClassReload=true即可 (使用的是 SpringLoaded 来进行热加载,并自动设置 reloadOnClassChange=false):
gretty {
port = 80
contextPath = '/'
servletContainer = 'tomcat7'
managedClassReload = true
recompileOnSourceChange = false // 禁止自动编译过度频繁的进行热部署
}
多模块工程
parent是父模块mix1和mix2是子模块
└── parent
├── mix1
│ ├── build.gradle
│ └── src
│ └── main
│ ├── java
│ └── resources
├── mix2
│ ├── build.gradle
│ └── src
│ └── main
│ ├── java
│ └── resources
├── build.gradle
└── settings.gradle
// parent/settings.gradle
include 'mix1'
include 'mix2'
// parent/build.gradle
// 所有模块生效
allprojects {
ext {
// gradle build or gradle -Dprofile=product build
profile = System.getProperty("profile", "dev")
}
println '++ Building: ' + project.name
}
// 所有子项目的通用配置
subprojects {
apply plugin: 'java'
tasks.withType(JavaCompile) {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
[compileJava, compileTestJava, javadoc]*.options*.encoding = 'UTF-8'
repositories {
mavenLocal()
mavenCentral()
}
}
// 某一个指定模块生效
project('mix1') {
println 'Building module mix1'
}
// 多个匹配的子模块生效
configure(subprojects.findAll {
it.name.equals('mix1') ||
it.name.equals('mix2')
}) {
apply plugin: 'java'
}
进入 parent 目录:
- 执行
gradle build构建所有的模块 - 执行
gradle :mix1:build构建子模块mix1
获取路径
println "${rootProject.projectDir}/config"
不能用
println ${rootProject.projectDir} + "/config"
settings.gradle
除了构建脚本文件,Gradle 还定义了一个约定名称的设置文件(默认为settings.gradle),该文件在初始化阶段被执行,对于多项目构建必须保证在根目录下有 settings.gradle 文件,对于单项目构建设置文件是可选的
强制 Gradle 使用 UTF-8
打开 gradle/bin 目录下的 gradle.bat 文件,修改 12 行附近的代码为
set DEFAULT_JVM_OPTS="-Dfile.encoding=UTF-8"
或者
gradle.properties 里添加
systemProp.file.encoding=UTF-8
创建工程目录结构
Gradle 默认没有提供创建各种项目目录结构的任务,但是可以使用 gradle-templates 来创建工程的目录结构。
apply plugin: 'java'
apply plugin: 'templates'
repositories {
mavenCentral()
}
buildscript {
repositories {
maven {
url 'http://dl.bintray.com/cjstehno/public'
}
}
dependencies {
classpath 'gradle-templates:gradle-templates:1.5'
}
}
运行 gradle tasks 可以看到有很多创建不同项目结构的任务
- 使用
gradle initJavaProject创建 Java 应用程序的目录结构 - 使用
gradle initWebappProject创建 Web 项目的目录结构
使用 Spring 的应用程序打包
Gradle 默认的打包任务 jar 不能带上依赖的类,在有依赖 Spring 的项目中,最好是使用 shadowJar 来打包,其会合并 spring 冲突的配置文件,例如 fatJar 则不会。
如果是可执行的 jar 包,配置 mainClassName 为 jar 包启动运行的类,否则可以忽略掉。
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
buildscript {
repositories { jcenter() }
dependencies { classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.3' }
}
mainClassName = 'Foo'
jar {
manifest { attributes 'Main-Class': mainClassName }
}
// 打包命令: gradle clean shadowJar
shadowJar {
mergeServiceFiles('META-INF/spring.*')
}
打包时只要指定的 jar 包,解压
war {
// 打包时只包含以下几个 jar 包
classpath = classpath.filter { file ->
file.name.startsWith('javaee-mvc-framework') ||
file.name.startsWith('e-platform-client') ||
file.name.equals('main')
}
archiveName 'qa.zip' // 默认为 qa.war
def zipFile = file("$buildDir/libs/qa.zip")
doLast {
copy {
from zipFile
into "$rootProject.projectDir/output/$school/"
}
//解压
def outputDir = file("$rootProject.projectDir/output/qa")
delete outputDir
copy{
from zipTree(zipFile)
into outputDir
}
}
}