Java实践指南(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-03 00:12:22

点击下载

作者:(美) 菲利普·约翰逊(Phillip Johnson)

出版社:人民邮电出版社有限公司

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Java实践指南

Java实践指南试读:

版权声明

Authorized translation from the English language edition, entitled Java for the Real World by Phillip Johnson Copyright © 2017.All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the author. CHINESE language edition published by Posts & Telecom Press, Copyright © 2019.本书中文简体字版由Phillip Johnson授权人民邮电出版社独家出版。未经出版者书面许可,不得以任何方式复制或抄袭本书。版权所有,侵权必究。

引言

“所以,你打算把我调到开发岗位吗?”“嗯,我是这样想的。”从此,我成了一名Java开发者。不久,我便接手了一个写得很糟糕并且满是bug的ETL程序,它所依赖的框架早在我读高中的时候就已经废弃了,而且没有测试代码。我天真地想:我学Java差不多有一年了,对我来说,添加测试应该不难,只要仔细地重构代码就行了。但是,这些XML文件有什么用?独立文件中的SQL是怎么进入DAO和DAOImpl的?程序中为什么有Ant和Maven的构建脚本?(这个问题我一直没想明白。)Ant和Maven又是什么?我又是Google搜索,又是请教专家,还动手做了试验,最终才好不容易搞定了这些问题。然而,写完自己第一个真正的Java程序时,想起这种语言的巨大反差带给我的折磨,我仍然惊魂甫定。多年后,我晋升为高级开发工程师,团队决定新招一名初级开发人员。来了一个小伙子,他大学毕业刚一年,在之前的工作中主要使用JavaScript。但是,他在学校学过Java,并且很有天分。实际上,他的毕业设计是用C++语言从零开始编写了一个3D图形渲染器。入职第一天,我给他展示了一个小的Web应用,这个应用以后就由他来做,并向他介绍了整个项目。很快,我就发现他对Java的理解只停留在语言层面,和几年前的我一模一样,而且他对Maven、MyBatis及Tomcat一概不懂。对我来说,为自己的无知找个借口很容易,比如没有系统地学习过计算机科学。这个小伙子虽然在学校学过编程,可还是被难住了。我们的求学道路截然不同,但结果都是一名不合格的Java开发者。事实证明,大多数Java教学只停留在对标准库的讲解上。我编写本书的初衷是希望自己当初开始学Java时能有这样一本书。我希望在你开始Java职业生涯时,本书能给你提供一些帮助。祝你编码快乐!

电子书

扫描如下二维码,即可购买本书电子版。第 1 章 入门介绍1.1 目标读者如书名所示,本书针对的是在商业环境中使用Java的人士。根据我的个人经验,学习Java体系几乎和学习Java语言一样困难。对经验丰富的程序员来说,相比于学习Java体系,学习Java语言可能没什么难度。虽然学习Java语言有大量工具可利用,但是介绍Java体系的资源并不多。本书旨在介绍编写专业Java软件所需的各种框架、工具和库。不管你是刚毕业,还是自学过编程,只要你想进入这个领域,本书都能为你提供大量实用知识,招聘主管会很看重你是否具备这些知识。实际工作中,你可能根本不需要写什么排序算法,但你肯定会遇到使用Hibernate实现持久化的Spring MVC Web应用。另一方面,如果你已经是一名专业开发者,并且理解了相关概念,那你更有可能问自己:“Java是如何实现……的?”本书不教授Java基础知识!阅读本书需要了解Java标准类库。如果你确实需要从头学习Java,建议你首先阅读Head First Java,然后再阅读一本比较新的深入讲解Java 8的书。如果你准备好学习如何开发企业级Java应用了,那就开始吧!1.2 如何使用本书

本书每章都会讲一个一般性概念,而且在某种程度上,各章相互依赖。所以,如果你有时间,建议从头到尾阅读本书。不过,如果你时间有限,可以只阅读感兴趣的章节。

文字解释的效果有限,所以本书会着重于代码呈现。相关代码都在正文中给出了,但简洁起见,省略了一些样板代码。访问本书中文版页面(http://www.ituring.com.cn/book/2438),可以找到完整的项目代码1。

1你也可提交中文版勘误。——编者注

示例代码形式如下。

OrderService.java27 public void save(Order order) {28 try(Session session = sessionFactory.openSession()) {29 Transaction tx = session.beginTransaction();30 session.persist(order);31 tx.commit();32 } // Session自动关闭33 }

其他用于讨论或演示的代码形式如下。public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); }}

本书篇幅不大,我们不会详细讲解任何工具。很多情况下,已有专门的图书详细讲解了某个工具。本书旨在简要介绍一些工具及其基本用法。如果你想学习更多相关内容,请进一步阅读每章后面的参考资源。

阅读本书过程中,你会见到如下标志。 这到底是什么?框架开发者喜欢用一些花哨的词描述其工具。比如,“Apache Maven是一个软件项目管理和理解工具”就很不容

易理解。阅读这些部分,你可以快速了解某个工具的具体用

途。

  Java疣Java是一门比较老的语言,向后兼容性较好。所以目前

还存在许多过时的用法和大量废弃的标准库,本书称其为“Java疣”。

  落后警告这是一个警告,提醒你注意在遗留系统中可能遇到的一

些东西。你应该尽量避免在新项目中使用这些东西。

  超前警告这与上一个标志正好相反。它提醒你注意Java中一些新

引入的“东西”,它们可能尚未被广泛采用。这不一定是坏

事,只是提醒你注意。

  更多内容这里给出了更多相关信息,以补充正文中提到的内容。

它们并不是特别重要,但是如果你感兴趣,可以把它作为延

伸阅读。1.3 搭建环境1.3.1 安装Java安装Java的方法有很多种,请根据你所用的操作系统和个人喜好来选择。  Homebrew(macOS):brew cask install java  Chocolatey(Windows):choco install jdk9  Apt-Get(Linux):sudo apt-get install default-jdk  SDKMAN!(类Unix):sdk install java官方安装方法:访问Oracle官网,根据相关提示进行安装。请确保安装的是JDK而非JRE。如果你选择了这种安装方法,请务必认真阅读Oracle JDK的许可协议(相关内容见下一章)。这些工具会把Java放到你的PATH变量中。为了确认这一点,可在命令行中输入java -version,输出信息如下所示。java version "1.8.0_131"Java(TM) SE Runtime Environment (build 1.8.0_131-b11)Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)此外,你可能还需设置JAVA_HOME环境变量,许多使用Java的工具都会首先查看它。你也可以在一台机器上安装多个Java版本,只需把JAVA_HOME指向主版本即可,这在测试Java新版本时很有用。1.3.2 集成开发环境常用的Java集成开发环境(IDE)有三种,分别为Eclipse、IntelliJ和Netbeans。我青睐IntelliJ,因为它的功能集丰富,并且集成了大量开发框架。不过,这三者之中,只有IntelliJ推出了付费版。它的免费社区版也不错,我家中计算机安装的就是社区版。对于工作项目,强烈建议使用付费旗舰版。有些公司为了定制的插件和设置,明确要求开发者使用特定的IDE开发环境,实为多此一举。因为从技术上讲,在命令行中可以编译任何Java代码,所以开发者选用哪款IDE编写代码其实无所谓。第 2 章 Java虚拟机2.1 何为Java虚拟机多年来,支持多平台一直是Java的卖点之一。比如,你在Mac上编写和测试Java代码,然后将其部署到Windows服务器上,它也能正常运行。这是因为编译好的代码和操作系统之间有一个Java虚拟机(JVM),它可以把Java转换成本地系统调用。准确地说,具体承担这个转换任务的是一个JVM实例。JVM既可以指Java虚拟机规范,也可以指其某个实现。2.2 JVM版本Java维护者会定期更新JVM规范。通过这种方式,他们可以给Java添加新特性或对其进行改进。写作本书时,Oracle公司发布的Java最新版本是Java 1.9。方便起见,人们通常把Java 1.9简称为“Java 9”,把Java 1.8简称为“Java 8”,以此类推。 落后警告:过时的JVM

然而有些公司对新技术并不怎么上心,金融行业尤为突出。

有些Java学习资料、博客、新闻等设想读者用的是Java 8或

Java 9,实际上读者用的却是Java 7,甚至是Java 6。明确程序将来在哪个JVM版本上运行十分重要,在着手开发之前就应该确定下来。JVM版本不同,可使用的Java语言特性也不同。然而,不管你编写Java代码时使用的是哪个版本的JVM,你都可以在自己的机器上安装最新的JVM来运行。这是因为Java有着良好的向后兼容特性,比如,针对JVM 1.6编写的Java代码可以在JVM 1.8上正常运行。为了验证这一点,下面给出两个示例程序,它们的功能相同。NamesOld.java 1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class NamesOld { 5 public static void main(String[] args) { 6 List names = new ArrayList(); 7 names.add("Foo"); 8 names.add("Bar"); 9 for(String name : names) {10 System.out.println(name);11 }12 }13 }NamesNew.java 1 import java.util.ArrayList; 2 import java.util.List; 3 4 public class NamesNew { 5 public static void main(String[] args) { 6 List names = new ArrayList<>(); 7 names.add("Foo"); 8 names.add("Bar"); 9 names.forEach(System.out::println);10 }11 }针对两个不同版本的JVM,编译上面两段程序,结果如下所示。 javac -source 1.6javac -source 1.8NamesOld.java无错误无错误NamesNew.java两个编译错误无错误 Java疣:向后兼容性

Java维护者高瞻远瞩,让Java具备了良好的向后兼容性,这

可能是促使Java今天无处不在的原因之一。然而,这样做也

带来了许多“包袱”,如下所示。● 自1997年以来,废弃了java.util.Date包中的一些方法。● 在很大程度上,java.time.*已经取代java.util.Date包。● 泛型只用于编译时检查,运行时会被清除。● const和goto两个关键字被保留,但并未实现。● 所有基本类型都有封装类,比如int和java.lang.Integer,boolean和java.lang.Boolean,等等。● 通常应该尽量避免使用Hashtable和Vector集合,而使用HashMap和ArrayList。如果你需要的集合要用于并发编程,那么应该考虑使用java.util.concurrent包。2.3 JVM种类其实Oracle推出了两款JVM产品,即Oracle JVM和OpenJDK JVM。几乎在所有情况下,任选一个即可。建议选择在你的系统中最容易安装的那个。不过请注意,在Oracle JVM中存在一些许可限制,但OpenJDK没有。如果你在意这些许可条款,建议咨询公司的法务部门。另外值得一提的是,由于JVM规范是公开的,所以任何人都可以打造自己的JVM。事实上,有些人和有的公司也这样做了,比如IBM的J9、Azul的Zing、Excelsior的JET等。这些第三方JVM实现都有各自的宣传噱头,但通常可以归结为以下三个方面:针对不同的操作系统、性能提升或添加了新特性。Oracle JVM和OpenJDK JVM的区别

两者区别不大。Oracle官方博客中写道:

……Oracle JDK是在OpenJDK 7基础上发布的,添加了更多

功能,比如部署代码,包含了Oracle对Java Plugin和Java

WebStart的实现,以及一些闭源第三方组件(比如Graphics

Rasterizer)和一些开源第三方组件(像Rhino),还有其他

一些零碎的东西,比如额外的文档或第三方字体等。

Henrik Stahl,“Java 7 Questions & Answers”,2011年8月11

日第 3 章 构建工具除非你的Java程序很短小,不然使用命令行编译Java程序就是自找麻烦,下面举例说明。首先介绍一个冰激凌商店程序——IScream,它是本书大部分示例代码的背景。IScream有如下两个类。DailySpecialService.java 1 package com.letstalkdata.iscream.service; 2 3 import com.google.common.collect.Lists; 4 import java.util.List; 5 6 public class DailySpecialService { 7 8 public List getSpecials() { 9 return Lists.newArrayList("Salty Caramel", "Coconut Chip", "Maui Mango");10 }11 }Application.java 1 package com.letstalkdata.iscream; 2 3 import com.letstalkdata.iscream.service.DailySpecialService; 4 import java.util.List; 5 6 public class Application { 7 public static void main(String[] args) { 8 System.out.println("Starting store!\n\n==============\n"); 910 DailySpecialService dailySpecialService = new DailySpecialService();11 List dailySpecials = dailySpecialService.getSpecials();1213 System.out.println("Today's specials are:");14 dailySpecials.forEach(s -> System.out.println(" - " + s));15 }16 }虽然这个例子有点刻意,但是它用到了Google的Guava代码库(guava-21.0.jar)。所以,在编译之前,我们必须下载guava-21.0.jar,并将其添加到项目中。 更多内容:.jar文件

.jar文件其实就是zip文件。你可以使用7-zip或unzip工具查看

其内容,就像查看其他zip文件一样。标准的.jar文件包含相

关Java类、资源,甚至还有其他便于分发的.jar文件。“瘦jar”

文件只包含作者创建的类和资源,而“胖jar”文件还包含

所依赖的所有第三方文件。你所使用的代码库几乎都是.jar

文件。示例程序的目录结构如下,它遵循Java文件夹常用约定。.├── lib│ └── guava-21.0.jar└── src └── main └── java └── com └── letstalkdata └── iscream ├── Application.java └── service └── DailySpecialService.java 更多内容:Java文件夹结构

Java类是以包的形式组织的,定义包时要在文件顶部使用

package关键字。依据约定,包名通常以域名(比如

com.google)开头,接着是部门名、代码用途等。这样会形

成长长的包名。由于包和目录存在一一对应的关系,所以最

终得到的目录结构也是层层嵌套的。

另一个约定是把程序或库代码的整个目录结构放入另外一组

文件夹(src/main/java)中,而把测试代码放入src/test/java

中。当我们学习构建工具的更多相关内容时,了解这一点尤

为重要。至此,代码已经组织好了,所需的第三方库也准备好了,接下来该进行编译了。你准备好了吗?$ javac -cp ".:lib/*" src/main/java/com/letstalkdata/iscream/*.java\> src/main/java/com/letstalkdata/iscream/service/*.java首先,我们要告诉Java编译器依赖文件的位置。Java会查找classpath,这可以通过环境变量进行设置。更常见的做法是在编译时使用-cp参数(如果你用的是Windows,请使用分号“;”而非冒号“:”把classpath分开)。接下来,我们要告诉编译器要编译哪些文件。使用*通配符能简化工作,但是我们仍然需要指定两个目录(而一个真实的应用程序往往有几十个目录)。运行上面的命令后,Java编译系统会在源代码所在的目录下生成杂乱的.class文件。为了避免出现这种情况,通常如下操作。$ javac -cp ".:lib/*" src/main/java/com/letstalkdata/iscream/*.java\> src/main/java/com/letstalkdata/iscream/service/*.java -d ./out编译时,借助-d选项,可以另外指定编译后保存代码的位置。上面的代码使用了-d选项把编译得到的class文件保存到out文件夹中。out文件夹最好已经存在,否则javac不会运行。如果想让代码易于运行,可以创建一个“胖jar”。此处不详述细节,大致的做法是:从Guava库中提取所需的类,然后创建一个MANIFEST.MF文件,用以指定程序运行时所需的所有代码,之后调用jar命令,把需要的所有Guava类和你的类包含在out目录中。为了解决上面这些烦琐的问题,人们开发出了构建工具。3.1 Ant40多年来,人们一直使用make程序把源代码转换成应用程序。因此,在早期的Java中,使用make就是顺理成章的事了。然而C程序的许多假设和约定并没有很好地转移到Java体系中。为了方便开发Java Tomcat应用程序,James Duncan Davidson编写出了Ant工具。很快,其他开源项目也开始使用Ant,从此Ant工具迅速普及开来。 这到底是什么?

Ant是一个管理Java编译过程的工具。它的可扩展性很强,

常用于编译代码、运行测试、创建构建工件、部署文件等。  落后警告:Ant

尽管早期Ant被广泛使用,但现在正逐渐被Maven、Gradle

等新的构建工具淘汰。3.1.1 构建文件Ant构建文件以XML格式编写,通常称作build.xml。一说到XML文件,有些人就畏缩,但请放心,小的XML并不复杂。在Ant中,不同的编译阶段叫作“目标”(target)。在构建文件中定义好目标之后,就可以使用ant TARGET命令进行调用,其中TARGET指目标名称。常见目标如下所示。build.xml 7 8 9 上面的clean目标用于“从头开始”,并且删除所有已有构件。build.xml11 12 13 16 显然,compile目标把Java源代码编译成class文件。请注意,Java源代码文件根目录设置为src/main/java。build.xml18 19 20 21 jar目标把编译好的class文件打包成.jar文件,并将其放入指定目录中。build.xml23 24 25 26 27 28 29 30 最后,run目标将从指定的主类运行整个应用程序。记得把Google Guava库放入classpath中,如下所示。build.xml 3 4 5 细心的话,你会发现compile目标中已经引用了classpath(classpathref= "classpath")。上面的文件中还出现了**/*,这是一种Ant匹配模式,类似于超级通配符,用于递归包含所有匹配文件。完整的构建文件如下。build.xml 1 2 3 4 5 6 7 8 9 1011 12 13 16 1718 19 20 21 2223 24 25 26 27 28 29 30 3132 定义好这些目标之后,接下来就可以运行ant clean、ant compile、ant jar、ant run命令来编译、构建和运行写好的应用程序了。当然,实际项目的构建文件可能比上面那个复杂得多。Ant提供了大量内置任务,用户也可以自定义任务。一个标准的构建任务包括移动文件、汇集文档、运行测试、发布构件等。如果你很幸运,接手一个维护良好的项目,那么构建文件或许可以原封不动地正常工作。否则,你可能需要手动对特定的计算机调整构建文件。调整时,要留心构建文件所引用的.properties文件,里面可能包含配置文件路径、环境设置等。3.1.2 使用Ivy管理依赖Ant有一个缺点——不支持依赖管理。构建程序时,我们仍需手动下载第三方Guava库,并在构建文件中指明其路径。Ivy工具可以为Ant添加依赖管理功能。如果项目使用了Ivy,那么项目根目录下会存在一个ivy.xml文件,就在Ant build.xml文件旁。前面示例项目的ivy.xml文件如下所示。ivy.xml 1 2 3 4 5 6 当然,不能随意设置依赖属性。通常,查找依赖属性最简单的方法是去所用库的官网,或者访问MVNRepository网站。就Guava库来说,你可以访问MVNRepository网站,在搜索框中输入“guava”,点击所需版本,再点击“Ivy”选项卡,即可得到依赖属性。图3-1 MVNRepository网站上的Guava接下来需要对Ant的构建文件做一些修改。(1) 修改第一行,添加Ivy库。(2) 添加一个目标,以解析依赖。 至此,我们就可以运行ant resolve命令来获取依赖,并将其放入lib文件夹中了。这一切都是自动进行的,无须手动操作。3.1.3 小结虽然编写构建脚本要花些时间,但使用它的好处显而易见,借助它,你不必手动把命令传递给Java。当然,Ant自身也有一些问题。首先,Ant脚本的强制标准不多。这提供了极大的灵活性,但代价是每个构建文件完全不同。就像你懂Java并不意味着能读懂所有代码库一样,了解Ant并不意味着你能读懂所有Ant文件,通常你要花些时间才能理解。其次,Ant本身不限制构建文件的长度,这意味着它可以变得很长,有的build.xml文件行数甚至超过2000。最后,Ant不支持依赖管理功能,需要配合Ivy工具使用。除了上面这些缺点外,Ant构建脚本还有其他一些不足,这最终促成了2000年初Maven的诞生。3.2 Maven

Maven其实是两个工具的集合:一个依赖管理器和一个构建工具。类似于Ant,Maven也是基于XML的,但与Ant不同的是,它的标准相当严格。而且,Maven是声明式的,允许用户定义构建目标,而不是方法。这些优点使得Maven大受欢迎,构建文件在整个项目中更为标准化,开发者定制这些文件只需花很少的时间。因此,Maven在某种程度上成了Java体系中事实上的标准。2016年的一次调查显示,68%的开发者将Maven作为主要构建工具。 这到底是什么?Maven工具用于管理Java代码库的整个构建周期:获取

依赖、编译代码、运行测试、创建构建工件、部署文件等。

此外,Maven还支持扩展,用户可以使用插件运行自定义任

务。3.2.1 Maven任务

Maven包含可以利用构建脚本实现的最常规的任务。这些任务称作phase,运行mvn PHASE(其中PHASE指任务名称)命令即可执行它们。最常规的任务如下所示。● 编译(compile):编译源代码。● 测试(test):在项目中运行单元测试。● 打包(package):创建代码发布包,比如.jar文件。● 验证(verify):在项目中运行集成测试。● 安装(install):创建本地可用的发布包,这些包可用于其他

Maven项目。● 部署(deploy):创建供他人使用的发布包,这些包可用于其他

Maven项目。(“他人”常指你所在团队或公司里的其他人,未必

是全世界。)

这些任务是可累加的,比如执行“打包”任务会引发“编译”和“测试”任务的执行。关于完整的Maven任务列表,请参阅“Lifecycle Reference”1。首次运行Maven构建项目时,应该执行“安装”(install)任务,这样会编译和测试整个项目,创建一个构建工件,并将其安装到本地Maven仓库中。

1https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference

虽然“清理”(clean)并非一个真正的任务,但mvn clean这个命令值得一提。执行此命令将清空你的本地构建目录(比如/target),删除编译好的类、资源、包等。理论上,只需运行mvn install命令,构建目录就会自动更新。不过很多开发者(包括我本人)发现有时它不起作用,因而习惯运行mvn clean install命令强制从头构建项目。3.2.2 项目对象模型文件

我们将Maven构建文件称为“项目对象模型文件”(POM),它以pom.xml的形式存储在项目的根目录下。为了让Maven能够正常工作,项目需要采用如下目录结构。.├── pom.xml└── src ├── main │ ├── java │ │ <-- Java代码在此 │ ├── resources │ │ <-- 应用程序或库所需的非代码文件 └── test ├── java │ <-- Java测试 ├── resources │ <--测试所需的非代码文件

POM文件顶部的标签通常如下所示。

pom.xml 4 com.letstalkdata 5 iscream 6 0.0.1-SNAPSHOT 7 jar● groupId:指明你的公司、团队或组织单位。● artifactId:POM构建的构件名。● version:构件版本号。构建成功后,后缀-SNAPSHOT表示

mvninstall和mvndeploy会自动替换构件。对于发布版本,你应该

删除此后缀。● packaging:待构建的构件类型。

下面介绍依赖。前面提过,Maven内置了依赖管理功能。示例项目的依赖如下所示。

pom.xml13 14 15 com.google.guava16 guava17 21.018 19

和Ivy一样,查找正确值的最简单方法是访问项目官网或者MVNRepository网站。

POM的最后一部分是build部分,包含构建可执行文件(.jar文件)所需的配置。3.2.3 插件

Maven长盛不衰的关键是其借由插件带来的强大扩展性。技术在不断变化,而Maven依然可以存活下来是因为它可以扩展丰富的第三方插件。比如,现在你可以找到各种各样的Maven插件,包括Web框架、文档生成器、Android、Docker等。

对于示例项目,我们只需用到Apache的一个官方插件——Shade,该插件可以构建“胖”jar文件。

pom.xml20 21 22 23 org.apache.maven.plugins24 maven-shade-plugin25 2.326 27 28 package29 30 shade31 32 33 34 36 37 com.letstalkdata.iscream.Application38 39 40 41 42 43

上面的代码涉及很多属性,但这里重点关注phase(package)和goal(shade)。这意味着当你运行mvnpackage(或者任何更高层次的任务)时,相关插件的shade目标就会执行,这里用于构建“胖”jar文件。

使用插件的不便之处是,必须把它们挂接到Maven的生命周期中。在上面的示例中,Shade插件已经挂接到了package。目标是不能独立存在的,创建自己的任务(phases)需要更多XML模板。

使用插件的另一个难题是其作用并不直观,而且如果缺少好的文档,也很难配置正确。比如,为了告诉插件主类是哪一个,我们必须在POM中向下深入六层。由于配置是通过XML进行的,所以可能对某个合法XML文件,插件能够读取它,但是不知道如何解释它,这常常会引起一些费解的错误信息。建议查找相关文档,从你参与的项目中找一个能够正常运作的例子,或者去Stack Overflow寻求帮助。从零开始配置插件往往是徒劳的。

至此,你就可以运行mvn package命令了,然后target文件夹中会生成iscream-0.0.1-SNAPSHOT.jar文件。接着,运行java -jar iscream-0.0.1-SNAPSHOT.jar,你会看到熟悉的程序输出。3.2.4 仓库和发布

尽管上面的构建并不需要仓库(repositories)和发布管理(distributionManagement),但是在公司内部项目中它们相当常见,值得一提。

在Maven中,仓库用于存储构件,并且Maven可以访问它。默认情况下,Maven认识Maven Central仓库并会使用它。首次构建应用程序时,构件会下载到本地仓库中。有人打趣说:这是在下载整个互联网,因为Maven遍历的依赖树好像无穷无尽。不过,一旦这些构件下载下来并且保存到你的本地计算机中,以后复用的时候就会非常快了。如果项目需要使用的构件存储在一个内部仓库中,或者使用的构件不在Maven Central中,那么你应该添加额外的仓库,代码如下所示。 xyzRepo Company XYZ Repo http://some-server/repo

如果你指定了多个仓库,Maven会按照指定顺序检查这些仓库。

当你需要部署构件时,就要用到distributionManagement部分了。如果你正在开发一个内部库,并且其他开发者会使用它,那么就要用到distributionManagement了。示例如下。 false xyzRepo Company XYZ Repo http://some-server/repo true xyzSnapRepo Company XYZ Snapshot Repo http://some-server/repo-snapshots legacy  更多内容:仓库不管你所在团队的规模如何,如果要在项目中使用内部

开发的库,最好创建一个内部仓库。否则,你必须把库保存

到源代码控制中。目前最流行的仓库管理器是Sonatype

Nexus,Artifactory也在日趋走红。当然,借助自己的Maven仓库,你可以保存任何构件,

不仅仅局限于内部库。建议保存Maven Central中没有的第

三方构件,比如微软的SQL Server数据库驱动程序。你还可

以存储Maven Central中存在的构件,以加快下载速度或者

减少项目的版本碎片。事实上,有些公司只允许开发者使用

企业存储库中的构件。3.2.5 小结

尽管Maven在简化项目构建方面已经取得了很大进步,但在使用Maven的过程中我们还是会碰到一些棘手的问题。前面提到了使用插件时的一些问题,此外还存在一个所谓的“Maven方式”问题。当某个构建不符合Maven的要求时,就会很难进行下去。许多项目都是“正常的……除了我们不得不做一些奇怪的事”。而且,构建过程中“怪事”越多,Maven就越不如意。虽然我不太同意一位博客作者的观点,他说“Maven构建是一个无尽而绝望的循环,它将你慢慢拖入地狱最深处、最黑暗的深渊……”,但我能够理解!

如果把Ant的灵活性和Maven的众多优点结合起来,那岂不是更好?!这正是Gradle试图实现的目标。3.3 Gradle第一眼看到Gradle构建脚本时,也许你会惊讶于它并未采用XML格式。事实上,Gradle使用了一种基于Groovy(一种基于JVM的敏捷开发语言)的领域特定语言(DSL)。 更多内容:Groovy

JVM规范是免费且公开的,人们可以创造出新的编程语言,

并且使用这些编程语言编写的源代码能够编译成Java字节

码。Groovy就是这样一种语言。虽然有时人们视其为脚本

语言(主要因为不需要定义任何类就能运行代码),但是你

完全可以用它编写整个应用程序。试试吧!def name = 'World'println("Hello, $name!")DSL定义了构建文件的核心部分和具体的构建步骤(也称“任务”)。其可扩展性使得定义任务很容易。当然,Gradle也拥有丰富的第三方插件库。下面详细介绍。 超前警告:Gradle

尽管Gradle越来越流行,但它还是个新事物。由于整个Java

体系进展缓慢,所以只在开源项目中见到它就不足为奇了。3.3.1 构建文件Gradle构建文件名是build.gradle,并且从配置构建环境开始。因为示例项目需要用到一个“胖”jar插件,所以要把Shadow插件添加到构建脚本配置中。build.gradle 1 buildscript { 2 repositories { 3 jcenter() 4 } 5 dependencies { 6 classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4' 7 } 8 }为了下载插件,Gradle必须在包含各种构建索引的仓库中查找。有几个Gradle库很出名,常简称为mavenCentral()或jcenter()。说到仓库,Gradle团队决定不重新发明轮子,转而依靠现有的Maven和Ivy依赖体系。3.3.2 任务Ant中“目标”(target)和Maven中“任务”(phase)的含义都比较模糊,Gradle为构建步骤起了一个清晰合理的名字:任务(task)。我们可以通过Gradle的apply命令访问指定任务。(Gradle内置了java插件,所以我们不必在构建依赖中声明它。)build.gradle10 apply plugin: 'java'11 apply plugin: 'com.github.johnrengelman.shadow'java插件用于执行clean、compileJava、test等常规任务。shadow插件用于执行shadowJar任务,创建一个“胖”jar。运行gradle –q tasks命令,可以查看完整的任务列表。下面列出了一些最常规的任务。● assemble:组装项目输出。● build:组装和测试项目。● clean:删除构建目录。● jar:打包主要类。● javadoc:为主要源代码生成Javadoc API文档。● test:运行单元测试。任务配置在构建脚本中进行,先是任务名称,接着是一个花括号。配置shadowJar任务的示例如下。build.gradle26 shadowJar {27 baseName ='iscream'28 manifest {29 attributes 'Main-Class': 'com.letstalkdata.iscream.Application'30 }31 }你也可以在构建文件中自定义任务。由于Gradle DSL基于Groovy编程语言,所以几乎有无限可能。例如,下面这个任务负责打印要编译的文件,可以通过gradle printClasspath命令调用它。task printClasspath { sourceSets.each { source -> println(source) def tree = source.compileClasspath.getAsFileTree() tree.files.each { f -> println(f.name) } }}3.3.3 依赖管理前面介绍脚本构建时,讲过了管理插件依赖的方法,同样的方法也适用于管理代码依赖。我们再次创建一个repositories和一个dependencies。乍看上去,它们与前面buildscript中的好像一样,但实际上有很大不同。buildscript内部的repositories和dependencies用于运行构建本身,而buildscript外部的repositories和dependencies用于编译程序代码。build.gradle18 repositories {19 mavenCentral()20 }2122 dependencies {23 compile group: 'com.google.guava', name: 'guava', version: '21.0'24 }完整的构建脚本如下。build.gradle 1 buildscript { 2 repositories { 3 jcenter() 4 } 5 dependencies { 6 classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4' 7 } 8 } 910 apply plugin: 'java'11 apply plugin: 'com.github.johnrengelman.shadow'1213 group = 'com.example'14 version ='0.0.1-SNAPSHOT'15 sourceCompatibility = 1.816 targetCompatibility = 1.81718 repositories {19 mavenCentral()20 }2122 dependencies {23 compile group: 'com.google.guava', name: 'guava', version: '21.0'24 }2526 shadowJar {27 baseName = 'iscream'28 manifest {29 attributes 'Main-Class': 'com.letstalkdata.iscream.Application'30 }31 }这样Gradle就知道如何找到项目依赖了。接着运行gradle shadowJar,创建一个包含Guava依赖项的胖jar。命令执行完毕后,会生成一个/build/lib/iscream-0.0.1-SNAPSHOT-all.jar,然后你可以以常规方式(java -jar ...)运行它了。如果项目需要用到存储在内部仓库中的构件,则用以下两种方式可以把其他仓库添加进去,具体取决于仓库的类型。01. Mavenrepositories { maven { url "http://repo.mycompany.com/maven2" }}02. Ivyrepositories { ivy { url "http://repo.mycompany.com/repo" }}3.3.4 Gradle守护进程也许你已经注意到了,每次运行Gradle都会出现如下信息。Starting a Gradle Daemon (subsequent builds will be faster)Grade Daemon是Gradle的一个特性,旨在加速项目构建。JVM启动慢是出了名的(每个新版本在这方面都有所改进)。Gradle需要在JVM中运行,所以JVM启动慢会拖慢项目构建速度。为了缓解这个问题,Gradle创建了一个长时间运行的后台进程。通过这个Gradle守护进程,只需启动一次JVM,之后就可以重复使用,无须再次启动,这大大缩短了项目的构建时间。在我的机器上,第一次运行gradle clean build命令清理IScream应用程序耗时5.35秒,第二次只花了1.898秒。如果你曾遇到项目构建速度慢的情况,可以使用--profile来弄清楚时间的使用情况。它会产生一个HTML报告,列出每个任务的耗时情况。

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载