提交 bc580e62 编写于 作者: W wizardforcel

2021-09-23 23:03:26

上级 47ec259e
......@@ -840,7 +840,7 @@ void printThreadsInfo() {
![Monitoring Threads](img/03_23.jpg)
`java.lang.management.ThreadMXBean`接口提供了许多关于线程的其他有用数据。有关此接口的更多信息,请参阅 Oracle 网站上的官方 API。请查看此链接:[https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/management/ThreadMXBean.html](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/management/ThreadMXBean.html)
`java.lang.management.ThreadMXBean`接口提供了许多关于线程的其他有用数据。有关此接口的更多信息,请参阅 Oracle 网站上的官方 API。[请查看此链接](https://docs.oracle.com/javase/8/docs/api/index.html?java/lang/management/ThreadMXBean.html)
在前面提到的线程列表中,您可能已经注意到了`Monitor Ctrl-Break`线程。此线程提供了另一种监视 JVM 进程中线程的方法。在 Windows 上按下*Ctrl**Break*键会导致 JVM 将线程转储打印到应用程序的标准输出中。在 Oracle Solaris 或 Linux 操作系统上,组合使用*Ctrl*键和反斜杠*\*也会产生相同的效果。这就引出了线程监控的外部工具。
......@@ -854,7 +854,7 @@ void printThreadsInfo() {
### 注
有关这些和其他诊断工具的更多详细信息,请参见 Oracle 官方文档[https://docs.oracle.com/javase/9/troubleshoot/diagnostic-tools.htm](https://docs.oracle.com/javase/9/troubleshoot/diagnostic-tools.htm)
有关这些和其他诊断工具的更多详细信息,请参见 [Oracle 官方文档](https://docs.oracle.com/javase/9/troubleshoot/diagnostic-tools.htm)
# 调整线程池执行器的大小
......@@ -1091,7 +1091,7 @@ Lock lock = ...;
与任何大型项目一样,每个金字塔建筑都经历了相同的设计、规划、执行和交付生命周期。在这些阶段中的每一个阶段,一个持续的调整都在进行,一个复杂的项目之所以这样叫是有原因的。软件系统在这方面没有什么不同。我们设计、规划和构建它,然后不断地改变和调整。如果我们幸运的话,那么新的改变不会回到最初的阶段,也不需要改变设计。为了避免这些激烈的步骤,我们使用原型(如果使用瀑布模型)或迭代交付(如果采用敏捷过程)来早期发现可能的问题。像年轻的父母一样,我们时刻保持警惕,日夜监控孩子的进步。
正如我们在前面的一节中已经提到的,每个 JDK 9 安装都有几个诊断工具,或者除了这些工具之外,还可以用来监视 Java 应用程序。这些工具的完整列表(以及如何创建自定义工具的建议,如果需要)可以在 Oracle 网站上的正式 Java SE 文档中找到:[https://docs.oracle.com/javase/9/troubleshoot/diagnostic-tools.htm](https://docs.oracle.com/javase/9/troubleshoot/diagnostic-tools.htm)
正如我们在前面的一节中已经提到的,每个 JDK 9 安装都有几个诊断工具,或者除了这些工具之外,还可以用来监视 Java 应用程序。这些工具的完整列表(以及如何创建自定义工具的建议,如果需要)[可以在 Oracle 网站上的正式 Java SE 文档中找到](https://docs.oracle.com/javase/9/troubleshoot/diagnostic-tools.htm)
使用这些工具可以识别应用程序的瓶颈,并通过编程或调优 JVM 本身或两者来解决它。最大的收益通常来自于良好的设计决策和使用某些编程技术和框架,其中一些我们在其他章节中已经描述过。在本节中,我们将研究在应用了所有可能的代码更改之后或更改代码不是选项时可用的选项,因此我们所能做的就是调优 JVM 本身。
......@@ -1128,7 +1128,7 @@ Lock lock = ...;
* **并发标记扫描(CMS)收集器**:它使用更短的垃圾收集暂停,但会占用更多处理器时间
* **垃圾优先(G1)收集器**:这适用于具有大内存的多处理器机器,但很可能满足垃圾收集暂停时间目标,同时实现高吞吐量。
Oracle 官方文档([https://docs.oracle.com/javase/9/gctuning/available-collectors.htm](https://docs.oracle.com/javase/9/gctuning/available-collectors.htm) 为垃圾收集选择提供了以下初始指导原则:
[Oracle 官方文档](https://docs.oracle.com/javase/9/gctuning/available-collectors.htm)为垃圾收集选择提供了以下初始指导原则:
* 如果应用程序有一个小数据集(大约 100 MB),则使用`-XX:+UseSerialGC`选项选择串行采集器
* 如果应用程序将在单处理器上运行,并且没有暂停时间要求,则使用`-XX:+UseSerialGC`选项选择串行采集器
......@@ -1335,7 +1335,7 @@ observable.subscribeOn(Schedulers.io())
`subscribeOn()`方法告诉`Observable`将数据放在哪个线程上。`Schedulers`类具有生成线程池的方法,这些线程池主要处理 I/O 操作(如我们的示例中所示),或计算量大(方法`computation()`),或为每个工作单元创建一个新线程(方法`newThread()`),以及其他一些方法,包括传入自定义线程池(方法`from(Executor executor)`
本书的格式不允许我们描述 RxJavaAPI 和其他反应流实现的所有丰富内容。他们的主旨反映在反应性宣言([http://www.reactivemanifesto.org/](http://www.reactivemanifesto.org/) 将反应式系统描述为新一代高性能软件解决方案。基于异步消息驱动流程和反应流,此类系统能够展示反应宣言中声明的质量:
本书的格式不允许我们描述 RxJavaAPI 和其他反应流实现的所有丰富内容。他们的主旨反映在[反应性宣言](http://www.reactivemanifesto.org/)将反应式系统描述为新一代高性能软件解决方案。基于异步消息驱动流程和反应流,此类系统能够展示反应宣言中声明的质量:
* **弹性**:可根据负载需要伸缩
* **更好的响应性**:在这里,可以使用异步调用并行处理
......
......@@ -16,7 +16,7 @@
在前面的章节中,我们演示了具有功能接口和并行流的 lambda 如何使并发处理成为每个 Java 程序员工具包的一部分。人们可以很容易地利用这一功能,只需最少的指导(如果有的话)。
在本章中,我们将描述其他一些旧的(在 Java9 之前)和新的 Java 特性和 API,它们允许对并发进行更多的控制。自 Java5 以来,高级并发 JavaAPI 就一直存在。JDK 增强方案(JEP)266,*更多并发更新*[http://openjdk.java.net/jeps/266](http://openjdk.java.net/jeps/266) ),引入到`java.util.concurrent` 包中的 Java 9
在本章中,我们将描述其他一些旧的(在 Java9 之前)和新的 Java 特性和 API,它们允许对并发进行更多的控制。自 Java5 以来,高级并发 JavaAPI 就一直存在。JDK 增强方案(JEP)266,[*更多并发更新*](http://openjdk.java.net/jeps/266),在 Java 9 引入到`java.util.concurrent`包中
一个可互操作的发布-订阅框架,对 CompletableFuture API 的增强,以及各种其他改进
......@@ -651,7 +651,7 @@ int getSomething(AnotherMutableClass amc, String whatever){
![](img/c3cdf125-0dbf-4fec-96b7-379aed0651a6.png)
这正是 Javadoc 所警告的([https://docs.oracle.com/cd/E17802_01/j2se/j2se/1.5.0/jcp/beta2/apidiffs/java/util/concurrent/CopyOnWriteArrayList.html](https://docs.oracle.com/cd/E17802_01/j2se/j2se/1.5.0/jcp/beta2/apidiffs/java/util/concurrent/CopyOnWriteArrayList.html)
[这正是 Javadoc 所警告的](https://docs.oracle.com/cd/E17802_01/j2se/j2se/1.5.0/jcp/beta2/apidiffs/java/util/concurrent/CopyOnWriteArrayList.html)
不支持迭代器本身(删除、设置和添加)上的元素更改操作。这些方法引发 UnsupportedOperationException
......@@ -1483,7 +1483,7 @@ List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
成功完成(未引发异常),如果有。在正常或异常返回时,未完成的任务将被取消
前面的引用来自 Javadoc([https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html)。下面是执行此操作的代码示例:
前面的引用来自 [Javadoc](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html)。下面是执行此操作的代码示例:
```java
void invokeAnyCallables(ExecutorService execService,
......@@ -1857,7 +1857,7 @@ void subscribe(Flow.Subscriber<? super T> subscriber)
```
根据 Javadoc([https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/SubmissionPublisher.html](https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/SubmissionPublisher.html),这种方法,
根据 [Javadoc](https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/SubmissionPublisher.html),这种方法,
“如果可能,添加给定的`Flow.Subscriber<T>`,如果已经订阅,或者订阅尝试失败,则使用`IllegalStateException`调用`Flow.Subscriber<T>``onError()`方法;否则,使用新的`Flow.Subscription.`调用`Flow.Subscriber<T>``onSubscribe()`方法,订阅者可以通过调用此`Flow.Subscription``request()`方法启用接收项目。”并可能通过调用其`cancel()`方法取消订阅。”
......
......@@ -43,7 +43,7 @@ TDD 可以比我们目前所做的多得多。我们可以定义需求,与客
这就是规格说明的用武之地。我们不仅使用它们来持续验证代码,而且它们还充当可执行文档。它们总是最新的,因为如果它们不是最新的,它们的执行就会失败。与此同时,虽然代码本身应该以一种易于阅读和理解的方式编写,但规范提供了一种更简单、更快速的方式来理解导致我们编写一些实现代码的原因、逻辑和动机。
将代码用作文档并不排除其他类型。相反,关键不是要避免使用静态文档,而是要避免重复。当代码提供必要的详细信息时,请先使用它。在大多数情况下,这给我们留下了更高级别的文档,例如概述、系统的一般用途、使用的技术、环境设置、安装、构建和打包,以及其他类型的数据,这些数据更像是指南和快速启动信息,而不是详细信息。对于这些情况,一个简单的降价格式的`README`[http://whatismarkdown.com/](http://whatismarkdown.com/) 往往是最好的。
将代码用作文档并不排除其他类型。相反,关键不是要避免使用静态文档,而是要避免重复。当代码提供必要的详细信息时,请先使用它。在大多数情况下,这给我们留下了更高级别的文档,例如概述、系统的一般用途、使用的技术、环境设置、安装、构建和打包,以及其他类型的数据,这些数据更像是指南和快速启动信息,而不是详细信息。对于这些情况,一个简单的降价格式的[`README`](http://whatismarkdown.com/)往往是最好的。
对于所有基于代码的文档,TDD 是最好的启用码。到目前为止,我们只使用单位(方法)。我们还没有看到如何在更高的层次上应用 TDD,例如,功能规范。然而,在我们到达那里之前,让我们谈谈团队中的其他角色。
......@@ -221,7 +221,7 @@ Then book is removed
唯一值得注意的是,我们在适当的时候使用了相同的步骤(例如,`When user selects a book`。由于我们将很快尝试自动化所有这些场景,因此在同一步骤中使用相同的文本将通过复制代码节省一些时间。重要的是要在以最佳方式表达场景的自由度和自动化的易用性之间取得平衡。在我们现有的场景中还有一些东西可以修改,但是,在我们重构它们之前,让我们向您介绍 JBehave。
源代码可以在`tdd-java-ch08-books-store`Git 库的`00-story`分支中找到,位于[https://bitbucket.org/vfarcic/tdd-java-ch08-books-store/branch/00-story](https://bitbucket.org/vfarcic/tdd-java-ch07-books-store/branch/00-story)
[源代码可以在`tdd-java-ch08-books-store`Git 库的`00-story`分支中找到](https://bitbucket.org/vfarcic/tdd-java-ch07-books-store/branch/00-story)
# 杰伯哈夫
......@@ -267,9 +267,9 @@ public class Runner extends JUnitStories {
}
```
这是一段非常平淡无奇的代码,所以我们只对几个重要部分进行评论。被重写的方法`storyPaths`将我们的故事文件的位置设置为`stories/**/*.story`路径。这是一个标准的 Apache Ant([http://ant.apache.org/](http://ant.apache.org/) 语法,当翻译成普通语言时,意味着将包括`stories`目录或任何子目录(`**`中以`.story`结尾的任何文件。另一个重要的重写方法是`stepsFactory`,它用于设置包含步骤定义的类(我们将很快处理它们)。在本例中,我们将其设置为一个名为`Steps`的类的实例(存储库中已经包含一个空类,我们稍后将使用该空类)。
这是一段非常平淡无奇的代码,所以我们只对几个重要部分进行评论。被重写的方法`storyPaths`将我们的故事文件的位置设置为`stories/**/*.story`路径。这是一个标准的 [Apache Ant](http://ant.apache.org/) 语法,当翻译成普通语言时,意味着将包括`stories`目录或任何子目录(`**`中以`.story`结尾的任何文件。另一个重要的重写方法是`stepsFactory`,它用于设置包含步骤定义的类(我们将很快处理它们)。在本例中,我们将其设置为一个名为`Steps`的类的实例(存储库中已经包含一个空类,我们稍后将使用该空类)。
源代码可以在`tdd-java-ch08-books-store`Git 库的`01-runner`分支中找到,位于[https://bitbucket.org/vfarcic/tdd-java-ch08-books-store/branch/01-runner](https://bitbucket.org/vfarcic/tdd-java-ch07-books-store/branch/01-runner)
[源代码可以在`tdd-java-ch08-books-store`Git 库的`01-runner`分支中找到](https://bitbucket.org/vfarcic/tdd-java-ch07-books-store/branch/01-runner)
现在我们已经完成了跑步,是时候开始跑步了,看看结果如何。
......@@ -305,7 +305,7 @@ JBehave 为我们创建了一个漂亮的报告,并将其放入`target/jbehave
Selenium 是一组可用于自动化浏览器的驱动程序。我们可以使用它们操纵浏览器和页面元素,例如,单击按钮或链接,填充表单字段,打开特定的 URL,等等。几乎所有浏览器都有驱动程序,包括 Android、Chrome、FireFox、Internet Explorer、Safari 等。我们最喜欢的是 PhantomJS,它是一种无头浏览器,无需任何 UI 即可工作。使用它运行故事比使用传统浏览器要快,而且我们经常使用它来获得有关 web 应用程序准备就绪的快速反馈。如果它按预期工作,我们可以继续并在应用程序应该支持的所有不同浏览器和版本中进行尝试。
有关硒的更多信息,请参见[http://www.seleniumhq.org/](http://www.seleniumhq.org/) ,支持的驱动列表位于[http://www.seleniumhq.org/projects/webdriver/](http://www.seleniumhq.org/projects/webdriver/)
有关 Selenium 的更多信息,请参见[这里](http://www.seleniumhq.org/) ,支持的驱动列表位于[这里](http://www.seleniumhq.org/projects/webdriver/)
虽然 Selenium 非常适合自动化浏览器,但它也有它的缺点,其中之一是它的操作级别非常低。例如,单击按钮很容易,只需一行代码即可完成:
......@@ -315,7 +315,7 @@ selenium.click("myLink")
如果 ID 为`myLink`的元素不存在,Selenium 将抛出异常,测试将失败。虽然我们希望在预期的元素不存在时测试失败,但在许多情况下它并不是那么简单。例如,我们的页面可能会动态加载,该元素只有在对服务器的异步请求得到响应后才会出现。出于这个原因,我们可能不仅要单击该元素,还要等待它可用,并且只有在达到超时时才会失败。虽然这可以用 Selenium 来完成,但它很单调且容易出错。此外,我们为什么要做别人已经做过的工作?向赛琳娜问好。
硒化物([http://selenide.org/](http://selenide.org/) 是一个围绕 Selenium`WebDrivers`的包装器,具有更简洁的 API、对 Ajax 的支持、使用 JQuery 风格的选择器等。我们将在所有 Web 步骤中使用 Selenide,您很快就会更加熟悉它
[Selenide](http://selenide.org/) 是一个围绕 Selenium`WebDrivers`的包装器,具有更简洁的 API、对 Ajax 的支持、使用 JQuery 风格的选择器等。我们将在所有 Web 步骤中使用 Selenide,您很快就会更加熟悉它
现在,让我们编写一些代码。
......@@ -502,7 +502,7 @@ public void thenBookIsRemoved() {
我们已经完成了步骤代码。现在,开发应用程序的人不仅有需求,而且有方法验证每个行为(场景)。他可以一次一个场景地完成红绿重构周期。
源代码可以在`tdd-java-ch08-books-store`Git 库的`02-steps`分支中找到:[https://bitbucket.org/vfarcic/tdd-java-ch08-books-store/branch/02-steps](https://bitbucket.org/vfarcic/tdd-java-ch07-books-store/branch/02-steps)
[源代码可以在`tdd-java-ch08-books-store`Git 库的`02-steps`分支中找到](https://bitbucket.org/vfarcic/tdd-java-ch07-books-store/branch/02-steps)
# 最终验证
......
......@@ -105,7 +105,7 @@ public class TicTacToe {
也许你已经意识到了这一点,但有一个陷阱。未检查`RuntimeException`块中的消息是否正确;甚至代码覆盖率也显示它覆盖了该行中的所有分支。
什么是覆盖率?
覆盖率是一种度量,用于描述特定测试套件测试程序源代码的程度。资料来源:[http://en.wikipedia.org/wiki/Code_coverage](http://en.wikipedia.org/wiki/Code_coverage)
覆盖率是一种度量,用于描述特定测试套件测试程序源代码的程度。[资料来源](http://en.wikipedia.org/wiki/Code_coverage)
让我们设想一个单端到端测试,它涵盖了代码的一个简单部分。此测试将获得较高的覆盖率,但安全性不高,因为还有许多其他部分尚未覆盖。
......@@ -622,7 +622,7 @@ PO 确认通过`status`搜索书籍现在已经改变,它还允许搜索任何
在本例中,整个中间端作为一个独立端工作,使用内存持久性。如果将持久性保存到数据库中,则可以使用相同的算法,但是我们需要一些额外的代码来在测试运行之间清理和填充数据库。
我们将使用 DbUnit。更多信息请参见[http://dbunit.sourceforge.net/](http://dbunit.sourceforge.net/)
我们将使用 DbUnit。更多信息请参见[这里](http://dbunit.sourceforge.net/)
# 编写端到端测试用例
......@@ -631,7 +631,8 @@ PO 确认通过`status`搜索书籍现在已经改变,它还允许搜索任何
在我们的例子中,由于前端不需要重构,所以该工具可以是较低级别的。我们选择编写 HTTP 请求以进行端到端测试。
这些请求应该是自动的和可测试的,并且应该遵循所有现有的自动测试规则或规范。当我们在编写这些测试时发现了真正的应用程序行为,我们决定在一个名为 Postman 的工具中编写一个 spike。
产品网站在这里:[https://www.getpostman.com/](https://www.getpostman.com/) 。这也可以通过名为 curl([的工具实现 http://curl.haxx.se/](http://curl.haxx.se/) )。
[产品网站在这里](https://www.getpostman.com/) 。这也可以通过名为 [curl](http://curl.haxx.se/) 的工具实现。
What is curl?  
curl is a command-line tool and library for transferring data with URL syntax, supporting `[...] HTTP`, `HTTPS, [...]`, `HTTP POST`, `HTTP PUT`, and `[...]`.
......@@ -683,7 +684,7 @@ The general idea here is this: depending on whether you want to save those tests
# 自动化测试用例
我们以编程方式启动服务器。为此,我们决定使用灰熊([https://javaee.github.io/grizzly/](https://javaee.github.io/grizzly/),允许我们使用 Jersey 的`ResourceConfig`(FQCN:`org.glassfish.jersey.server.ResourceConfig`)配置启动服务器,如测试`BooksEndpointTest`(片段)所示。
我们以编程方式启动服务器。为此,我们决定使用 [Grizzly](https://javaee.github.io/grizzly/),允许我们使用 Jersey 的`ResourceConfig`(FQCN:`org.glassfish.jersey.server.ResourceConfig`)配置启动服务器,如测试`BooksEndpointTest`(片段)所示。
代码可在[中找到 https://bitbucket.org/vfarcic/tdd-java-alexandria](https://bitbucket.org/vfarcic/tdd-java-alexandria)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册