文章目录
项目自动化介绍
构建工具的作用
-
依赖管理
对各种 Jars 包和版本的管理
-
测试、打包、发布
对项目代码进行测试,测试完成后,将项目代码进行打包,发布服务器上
主流的构建工具有那些?
![](http://img.zwer.xyz/blog/20200213173602.png)
Gradle 介绍
一个开源的项目自动化构建工具,建立在 Apache Ant 和 Apache Maven 概念的基础上,并引入了基于 Groovy 的特定领域语言(DSL),而不再使用 XML 形式管理构建脚本。
![](http://img.zwer.xyz/blog/20200213174609.png)
二十几岁正在为事业奋斗的男人就像搬砖工,
搬起砖,就没手抱你,放下砖,就不能养你。
--多么悲情的浪漫,可你有没有想过为什么不能兼顾?
Gradle 快速入门
准备
- 确保已经安装 JDK ,java -version
- 从 Gradle 官网下载 Gradle,https://gradel.org
安装
- 配置环境变量,
GRADLE_HOME
- 添加到 path,
%GRADLE_HOME%\bin
- 验证是否安装成功,
gradle -v
Groovy 介绍
Groovy 是用于 Java 虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性。
与 Java 相比
- Groovy 完全兼容 Java 的语言
- 分号是可选的
- 类 、方法默认是 public 的
- 编译器给属性自动添加 getter/setter 方法
- 属性可以直接用点号获取
- 最后一个表达式的值会被作为返回值
- == 等同于 equals(), 不会有 NullPointerException
Groovy 的高级特性
- assert 语句
- 可选类型定义
- 可选的括号
- 字符串
- 集合 API
- 闭包
基于 Gradle 创建 Java 项目
打开 IDEA,创建新项目
配置 Groovy
若不选择本地 Groovy ,IDEA 会自动从网络上下载 Groovy
打开 Groovy Console 测试
测试代码
public class ProjectVersion{
// 定义一个大版本号
private int major
// 定义一个小版本号
private int minor
// 提供有参构造方法
public ProjectVersion(int major, int minor){
this.major = major
this.minor = minor
}
// 提供 setter、getter 方法
public void setMajor(int major){
this.major = major;
}
public int getMajor(){
return this.major;
}
}
ProjectVersion v1 = new ProjectVersion(1, 0)
println v1.major
println v1.minor // Groovy 提供了 setter 、 getter 方法
ProjectVersion v2 = null
println v1 == v2 // 验证 == 等同于 equals 方法
Groovy 高效特性
- 可选类型定义(使用
def
关键字声明变量,类型自动推断) - 可选的括号
- 字符串(字符串,双字符串,三字符串)
- 集合 API
- 闭包(将函数作为参数传递)
// 可选类型定义
def version = 1
def g = 'gradle'
// assert 语句
//assert 1==1
// assert version == 1
// 可选的括号
//println version.getClass()
//println version
// 字符串
def s1 = 'Hello Gradle'
def s2 = "Hello ${g}"
def s3 = '''Hello
Gradle'''
//println s1
//println s2
//println s3
// 集合 API
def buildTools = ['ant', 'maven']
//buildTools.add('gradle')
buildTools << 'gradle'
//println buildTools
//println buildTools.getClass()
//println buildTools.size() == 3
def buildYears = ['ant':2000, 'maven':2004]
buildYears.gradle = 2008
//println buildYears.ant
//println buildYears['gradle']
//println buildYears.getClass()
// 闭包
def c1 = {
param ->
println "Hello ${param}"
}
def c2 = {
println "Hello c1"
}
def method1(Closure closure){ // 注意: Closure 不要导包
closure('c1')
}
def method2(Closure closure){
closure()
}
method1 c1 // 相当于 method1(c1)
method2 c2 // 相当于 method2(c2)
第一个 Gradle 项目
TODO 应用程序,只实现添加待办事项
-
TodoItem.java
package com.szxy; /** * @Author:zwer * @Date:2020/2/13 20:58 * @Description:com.szxy.com.szxy * @Version:1.0 **/ public class TodoItem { private String name; // 事项名称 private boolean hasDone; // 是否已经完成 public TodoItem(String name, boolean hasDone){ this.name = name; this.hasDone = hasDone; } public TodoItem(String name){ this(name, false); } public TodoItem(){} public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isHasDone() { return hasDone; } public void setHasDone(boolean hasDone) { this.hasDone = hasDone; } @Override public String toString() { return "name: "+name+" hasDone:"+(hasDone ? "has done it" : "need to do it"); } }
-
App
package com.szxy; import java.util.Scanner; /** * @Author:zwer * @Date:2020/2/13 20:56 * @Description:com.szxy * @Version:1.0 **/ public class App { public static void main(String[] args) { Scanner input = new Scanner(System.in); int i = 0; while(++i > 0){ System.out.println(i+" .Please input your todo:"); TodoItem todoItem = new TodoItem(input.nextLine()); System.out.println(todoItem); } } }
-
使用 Gradle 进行项目构建
点击 jar 按钮后,若构建成功,则会在 build/libs 目录生成 jar 包文件 -
在 IDAE 终端下运行 jar
java -classpath build/libs/20202013-todo-1.0-SNAPSHOT.jar com.szxy.App
第一个 Gradle 的 Web 项目
-
修改 build.gradle 文件
plugins { // id 'java' id 'war' // 官网 } group 'com.szxy' version '1.0-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' }
-
项目结构
-
index.html
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Todo</title> <script> function addTodo(){ let todo = document.getElementsByTagName("input")[0] let your_todo = document.getElementById("your_todo").getElementsByTagName("ul")[0] your_todo.innerHTML += "<li>"+ todo.value +"</li>" } function clearTodo(){ document.getElementsByTagName("input")[0].value = "" } </script> </head> <body> <div id="container" style="width:500px"> <h1>待办事项</h1> <hr/> <label>请输入你所需要的待办事项:</label> <input type="text" name="todo" /> <button onclick="addTodo()" >添加</button> <button onclick="clearTodo()">清空</button> <hr/> <h2>你确定的待办事项</h2> <div id="your_todo"> <ul></ul> </div> </div> </body> </html>
-
构建项目
-
点击 war 按钮,在 build/libs 目录下生成 war 包
-
war 包丢到 tomcat 目录下的 webapps 中,然后启动 tomcat,访问
http://localhost:8888/20202013-todo-1.0-SNAPSHOT/
Gradle 基本原理
构建脚本
构建块:Gradle 构建中的两个基本概念是项目(project) 和任务(task),每个构建至少包含 一个项目,项目中包含一个或多个任务。在多项目构建中,一个项目可以依赖于其他项目 ;类似的,任务可以形成一个依赖关系图来确保它们的执行顺序。
项目-任务之间的关系
项目(Project):一个项目代表一个正在构建的组件(比如一个 jar 文件),当构建启动后, Gradle 会基于 build.gradle 实例化一个 org.gradle.api.Project 类,并且能够通过 project 变量使其隐式可用。
- group 、name 、version
- apply 、dependencies、repositories、 task
- 属性的其他配置方式: ext、gradle.properties
Task (task): 任务对应 org.gradle.api.Task 。主要包括任务动作和任务依赖。任务动作定义了一个最小的工作单元。可以定义依赖于其他任务、动作序列和执行条件
- dependsOn
- doFirst 、doLast <<
自定义任务
自动创建目录结构
def createNewDir = {
path ->
File file = new File(path)
if(!file.exists()){
if(path.endsWith(".xml")){
file.createNewFile()
}
file.mkdirs()
}
}
task createJavaDir {
def paths = ['src/main/java', 'src/main/resources', 'src/test/java', 'src/test/resources']
doFirst {
paths.forEach(createNewDir)
}
}
task createWebAppDir {
dependsOn 'createJavaDir' // createWebAppDir 依赖于 createJavaDir
def paths = ['src/main/webapp', 'src/main/webapp/WEB-INF','src/main/webapp/WEB-INF/web.xml']
doLast {
paths.forEach(createNewDir)
}
}
构建生命周期
钩子方法
依赖管理
概述:几乎所有的基于 JVM 的软件都需要依赖外部类库来重用现有的功能。自动化的依赖管理可以明确依赖的版本,可以解决因传递性依赖带来的版本冲突
工件坐标: group name version
常用仓库: mavenLocal mavenCentral jcenter 自定义 maven 仓库 文件仓库
repositories { // 仓库使用顺序是从上往下
maven {
url '' // 私服
}
mavenLocal() // 本地仓库
mavenCentral() // 中央仓库
}
依赖传递:若 A->B, B->C, 则 A->C。若 A 依赖于 B,B 依赖于 C,则 A -> C
依赖阶段配置:编译代码:compile、runtime 测试代码:testCompile、testRuntime
大多依赖都是编译时依赖即 compile,只有少数情况下使用运行时依赖 runtime,比如 JDBC 的驱动属于运行时依赖。一般情况下使用别人的依赖时,依赖文档中会说明那种依赖的,若实在分不清依赖是编译时依赖还是运行时依赖,选择编译时依赖也没有问题。
解决版本冲突
当导入新的依赖于原有的依赖发生版本冲突(jar 包的版本不一致,导致版本冲突),Gradle 会自动处理版本冲突的 jar 包,若 Gradle 处理不了,则采用默认解决策略-出现版本冲突,则直接构建失败。
这里解决版本冲突在 Gradle 4.3 以下的版本中使用。
-
修改默认解决策略
configurations.all { resolutionStrategy{ failOnVersionConflict() // 出现版本冲突,则直接构建失败 } }
-
排除传递性依赖
compile('org.hibernate:hibernate-core:3.6.3.Final'){ exclude group:"org.slf4j", module:"slf4j-api" //transitive = false }
-
强制指定一个版本
configurations.all{ resolutionStrategy{ force 'org.slf4j:slf4j-api:1.7.24' } }
Gradle 深入实战
多项目构建
项目模块化:在企业项目中,包层次和类关系比较复杂,把代码拆分成模块通常是最佳实践,这需要你清晰的划分功能的边界,比如把业务逻辑和数据持久化分开来。项目符合高内聚低耦合时,模块化就变得很容易,这是一条非常好的软件开发实践
TODO 依赖关系:
model 模块下 build.gradle
文件中 dependencies 配置:
dependencies {
compile project(':model') // repository 依赖于 model
}
web 模块下 build.gradle
文件中 dependencies 配置:
dependencies {
compile project(':repository')
}
根目录下 setting.gradle
文件:
rootProject.name = 'todo'
include 'model'
include 'repository'
include 'web'
配置子项目
配置要求:
-
所有项目应用 Java 插件
-
Web 子项目打包成 WAR
-
所有项目添加 logback 日志功能
-
统一配置公共属性
项目范围:
多项目构建实战
根目录下 build.gradle
文件配置
allprojects { // 为所有模块配置 Java 插件
apply plugin: 'java'
sourceCompatibility = 1.8
}
subprojects {
repositories { // 仓库使用顺序是从上往下
mavenCentral() // 中央仓库
}
dependencies { // 所有项目添加 logback 日志功能
implementation 'com.hynnet:logback-classic:1.1.3'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
}
repositories { // 仓库使用顺序是从上往下
maven {
url '' // 私服
}
mavenLocal() // 本地仓库
mavenCentral() // 中央仓库
}
在根项目目录下新建 gradle.properties
文件,统一配置公共属性
group='com.szxy.todo'
version='2.0-SNAPSHOT'
自动化测试
概述:
一些开源的测试框架比如 Junit,TestNG 能够帮助我们编写可复用的结构化的测试,为了运行这些,你要先编译它们,就像编译源代码一样。测试代码的作用仅仅用于测试的情况,不应该被发布到生产环境中,需要把源代码和测试代码分开来。
项目布局:
测试配置(添加依赖):
dependencies {
testImplementation 'junit:junit:4.12'
}
test {
useJUnit()
maxHeapSize = '1G'
}
测试发现:
- 任何继承自
junit.framework.TestCase
或groovy.util.GroovyTestCase
的类 - 任何被
@RunWith
注解的类 - 任何至少包含一个被
@Test
注解的类
public class TodoRepositoryImplTest {
private TodoRepository repo = new TodoRepositoryImpl();
@Test
public void saveTest(){
TodoItem item = new TodoItem("eat food");
repo.save(item);
//Assert.assertNull(item.getName());
Assert.assertNotNull(item.getName());
}
}
发布
发布到本地或者远程:
配置 maven 插件
apply plugin: 'maven-publish'
publishing {
publications {
myPublish(MavenPublication){
groupId = 'com.szxy.todo'
version = '1.0'
from components.java
}
}
repositories {
maven {
name "myRepo"
url ""
}
}
}
Gradle 总结
慕课学习视频
Gradle 课程,老师讲的不错
这是 Gradle 课程链接地址,欢迎大家来一起学习,共同进步!