Java微服务(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-29 13:52:25

点击下载

作者:沙鲁巴·夏尔马 (Sourabh Sharma)

出版社:电子工业出版社

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

Java微服务

Java微服务试读:

前言

微服务(Microservices)架构是软件架构风格的一种。随着云平台的采用,企业应用程序的开发从整体应用程序转移到小型、轻量和过程驱动的组件,这种组件称为微服务。顾名思义,微服务是指小型服务。它们是设计可扩展、易于维护的应用程序的下一个重大事件。它不但使应用程序开发起来更容易,而且还提供了极大的灵活性来以最佳方式利用各种资源。

本书是帮助你构建供企业使用的微服务实现的实践指南。它还解释了领域驱动设计及其在微服务中的采用。它讲述了怎样构建更小型、更轻量、更快速的服务,同时确保其可以很方便地在生产环境中实施。它也讲述了企业应用程序开发从设计与开发,到部署、测试和实现安全性的完整生命周期。

本书包含的内容

第1章,一种解决方法,涉及大型软件项目的高层次设计,在生产环境中所面临的共同问题和解决问题的方法。

第2章,设置开发环境,讲述了如何设置开发环境,包括IDE和其他开发工具,以及不同的库。本章涉及创建基本项目到设置spring引导配置,以建立和发展第一个微服务。

第3章,领域驱动设计,通过引用一个示例项目为其余的章节设定基调。它使用此示例项目来驱动服务或应用程序的不同功能和领域组合来解释领域驱动设计。

第4章,实现微服务,讲述示例项目从设计到实现的过程。本章不仅涉及编码,还涉及微服务的不同方面——构建、单元测试和包装。在本章末尾,将完成一个可用于部署和使用的示例微服务项目。

第5章,部署和测试,讲述了如何采用不同的形式,包括独立部署和使用诸如Docker的容器来部署微服务。本章还将演示如何用Docker把我们的示例项目部署到诸如AWS的云服务上面。你还将掌握使用REST Java客户端和其他工具来测试微服务的知识。

第6章,实现微服务的安全性,解释如何利用身份验证和授权来保证微服务的安全。身份验证将使用基本身份验证和身份验证令牌来讲述。同样,授权将使用Spring Security来解释。本章还将解释常见的安全问题及对策。

第7章,利用微服务Web应用程序来使用服务,解释了如何利用Knockout、Require和Bootstrap JS库开发web应用程序(UI),构建使用微服务来显示数据的web应用程序的原型和一个小型实用程序项目(示例项目)的流程。

第8章,最佳做法和一般原则,讲述微服务设计的最佳做法和一般原则。本章还提供了有关使用行业做法进行微服务开发的详细信息和范例。本章还包含微服务实现会产生的错误,以及如何才能避免这类问题的几个例子。

第9章,故障排除指南,解释了在微服务及其解决方案的开发过程中会遇到的常见问题。这将帮助你顺利地掌握本书内容,并使学习过程轻松。

学习本书需要具备的条件

为了学习本书,可以使用至少具备2GB内存的安装了任何操作系统(Linux、Windows或Mac)的计算机;还需要NetBeans with Java、Maven、Spring Boot、Spring Cloud、Eureka Server、Docker和CI/CD的应用程序。对于Docker容器,可能需要一个单独的虚拟机或一个云主机,最好拥有16GB或更大的内存。

本书的受众

本书面向熟悉微服务架构,并对核心要素和微服务应用程序有一个合理的知识水平和理解,但现在想要深入了解如何有效地实施企业级微服务的Java开发人员。

版式约定

你会发现,本书采用了大量的文本样式,用以区分不同种类的信息。下面是这些样式和解释它们的含义的一些例子。

正文中的代码、数据库表名称、文件夹名称、文件名、文件扩展名、路径名、虚拟的URL、用户输入和Twitter句柄如下所示:“可以使用下面的实现创建Table实体,并且可以根据自己的需要添加属性”。

代码块的设置,如下所示︰public class Table extends BaseEntity { private int capacity; public Table(String name, BigInteger id, int capacity) { super(id, name); this.capacity = capacity; }

任何命令行输入或输出采用的格式如下:docker push localhost:5000/sourabhh/restaurant-service:PACKT-SNAPSHOT docker-compose pull警告或重要的说明在这样的方框中显示。提示和技巧以这样的形式出现。

下载示例代码

从http://www.broadview.com.cn下载所有已购买的博文视点书籍的示例代码文件。

勘误表

虽然我们已经尽力谨慎地确保内容的准确性,但错误仍然存在。如果你发现了书中的错误,包括正文和代码中的错误,请告诉我们,我们会非常感激。这样,你不仅帮助了其他读者,也帮助我们改进后续的出版。如发现任何勘误,可以在博文视点网站相应图书的页面提交勘误信息。一旦你找到的错误被证实,你提交的信息就会被接受,我们的网站也会发布这些勘误信息。你可以随时浏览图书页面,查看已发布的勘误信息。

参与本书翻译的人员有卢涛、李颖、卢林、陈克非、李洪秋、张慧珍、李又及、卢晓瑶、李阳、陈克翠、刘雯、汤有四。1 一种解决方法

作为先决条件,我希望你对微服务和软件架构能有一个基本了解。如果不是这样,我建议你用搜索引擎查一下,在解释并详细介绍它们的众多资源中锁定一个。这将帮助你彻底理解其概念和把握本书内容。

读完这本书,你就可以实现微服务,把它用于本地部署或云生产环境的部署,并学习完整的生命周期,包括设计、开发、测试和部署,以及持续集成和部署。本书是专门为实际使用而编写的,用来激发你作为解决方案架构师的智慧。你的学习将帮助你开发和交付任何类型的本地部署下的产品,包括SaaS、PaaS,等等。我们将主要使用Java和基于Java的框架工具,如Spring Boot和Jetty,我们还将使用Docker作为容器。从这里起,本书将用µServices来表示Microservices(微服务),除了用引号括起来的时候。(译者注:实际上只有少数章节用µServices,因此为了统一,µServices也译为微服务。)

在本章中,你将学习微服务的永存性及其演化过程。它强调了本地部署和基于云的产品面临的重大问题及微服务如何处理这些问题。本章还解释了在SaaS、企业级或大型应用程序的开发过程中遇到的常见问题及其解决方案。

在这一章,我们将学习以下主题:● 微服务和背景简介● 整体式架构● 整体式架构的限制● 微服务提供的灵活性与效益● 在诸如Docker的容器中部署微服务微服务的演变

Martin Fowler解释说:“‘微服务’一词是2011年5月在威尼斯附近举办的软件架构师讲习班上讨论的,用来描述参与者所见到的作为一种通用的架构风格的东西,其中有许多已经在最近得到研究。在2012年5月,同一个小组决定把‘微服务’作为这种东西最适当的名称。”

让我们了解一下它在过去几年的发展的一些背景。企业架构更多地从历史悠久的大型机计算,经过客户端-服务器架构(2层到n层)到面向服务的架构(service-oriented architecture,SOA)进化。

从SOA到微服务的转变不是一个由任何行业组织定义的标准,而是由许多组织实行的实用方法。SOA最终进化成为微服务。

Netflix架构师Adrian Cockcroft,把它形容为:“细粒度SOA。所以微服务是强调小型短暂组件的SOA。”

同样,以下引用Mike Gancarz(X windows系统的设计团队成员)的叙述,定义了UNIX哲学至高无上的一种感受,它同样适合微服务范式:“小即是美。”

微服务与SOA有许多共同的特点,比如将重点放在服务上,以及如何把一个服务与另一个服务解耦。SOA通过公开大多基于简单对象访问协议(SOAP)的API,围绕整体应用程序集成展开进化。因此,中间件,比如企业服务总线(ESB),对SOA是非常重要的。微服务的复杂度更低,即使它可能使用消息总线,也仅把它用于消息传输并且不包含任何逻辑。

Tony Pujals漂亮地定义了微服务:“在我的心理模型中,我认为微服务是自包含(如在容器中)的轻量进程,它们通过HTTP进行通信,用相对较小的工作量与仪式来创建和部署,将只集中在有限领域的API提供给它们的使用者。”整体式架构概述

微服务并不是新事物,它已经流传了很多年。其最近的崛起归功于其声望和知名度的提高。在微服务变得流行之前,被用于开发本地部署和云应用的主要是整体式架构。

整体式架构允许分别开发不同组件,如展示、应用程序逻辑、业务逻辑和数据访问对象(data access objects,DAO),然后你要么将它们一起打包在企业归档(enterprise archive,EAR)或web归档(web archive,WAR)文件中,要么将它们存储在某个单独的目录层次结构中(例如,Rails、NodeJS,等等)。

许多著名应用程序,如Netflix,已经使用微服务架构进行开发。此外,eBay、亚马逊和Groupon也都已经从整体式架构发展到微服务架构。

现在,你已经深入了解了微服务的背景和历史,接下来让我们讨论一种传统的方法,即整体式应用程序开发的局限性,并将其与微服务解决局限性的方法做比较。整体式架构的局限性与它的微服务解决方案的对比

正如我们所知,变化是永恒的。人类总是希望寻找更好的解决方案。这就是微服务如何发展成为了它今天的样子的原因,而且它可能会在未来进一步演变。今天,组织使用敏捷方法来开发应用程序,这是一种快节奏的开发环境,在云计算和分布式技术的发明以后,它的规模变得更大。许多人认为整体式架构也可能用于类似用途,并与敏捷方法契合,但微服务还为用于生产的应用程序的许多方面提供了更好的解决方案。

若要了解整体式设计和微服务的差别,让我们举一个餐馆订座应用程序的例子。这个应用程序可能包括很多个服务,如客户、订单、分析等服务,以及常规的组件,如展示和数据库组件。

我们将在这里探索三种不同的设计——传统的整体式设计、使用服务的整体式设计和微服务设计。

下面的关系图说明了传统的整体式应用程序设计。在SOA变得流行之前,这种设计一直被广泛应用:传统的整体式设计

在传统的整体式设计中,一切都被打包在同一个归档文件中,包括展示代码、应用程序逻辑和业务逻辑代码、DAO代码、与数据库文件或其他数据源进行交互有关的代码。

在SOA产生以后,应用程序开始基于服务来开发,在这种开发模式中,每个组件都为其他组件或外部实体提供服务。下面的关系图描述了提供不同服务的整体式应用程序,在这里,多个服务都被展示组件使用了。所有服务、展示组件或任何其他组件都被打包在一起:使用服务的整体式设计

下面的第三个设计描绘了微服务。在这里,每个组件都是自主的。每个组件都可以独立开发、构建、测试和部署。在这里,甚至应用程序UI组件也可以是一个使用微服务的客户端。在我们的示例中,为了举例说明,在微服务内部使用这个设计的层。

API网关提供接口,不同的客户端可以通过它访问个别的服务,并解决以下问题:● 如何让相同的服务给不同的客户端发送不同的响应。例如,预订

服务可以发送如下不同的响应、向移动客户端发送最小化的信息、

向桌面客户端发送详细信息,它们提供不同的细节,并向第三方

客户端发送不同的东西。● 某个响应可能需要从两个或多个服务中提取信息:微服务设计

所有的示例设计关系图都是非常高层次的设计,观察了这些之后,你可能会发现,在整体式设计中,各个组件全被捆绑在一起,并且互相紧密耦合。

所有的服务都是相同的捆绑包的一部分。同样,在第二个设计的关系图中,可以看到第一个关系图的变体,在这个设计中,所有服务都可以有其自己的层,并形成不同的API,但如图所示,这些也全都捆绑在一起。

相反,在微服务中,设计组件并未捆绑在一起,并且具有松散的耦合。每个服务都有其自己的层,而DB被捆绑在一个单独的归档文件中。所有这些已部署的服务都提供它们特定的API,例如客户、预订或分析。这些API都是准备就绪可供使用的,甚至连UI也是单独部署,并使用微服务设计的。因此,它比对应的整体式设计具备更多优点。尽管如此,我还是要提醒你,有一些特殊的情况下,整体式的应用程序开发模式是非常成功的,比如Etsy和对等电子商务web应用程序。一维的可扩展性

随着整体式应用程序所有的部件都被打包在一起,它在扩展时是庞大的,需要扩展一切。例如,在餐馆订座应用程序中,即使你想要只扩展餐桌预订服务,也要扩展整个应用程序,而不能单独扩展餐桌预订服务。它未能以最佳方式利用资源。

此外,这个扩展是一维的。运行应用程序的多个副本会提供交易量增加的扩展。运营团队可以使用基于服务器集群或云负载的负载平衡器来调整应用程序副本的数量。每个副本都将访问相同的数据源,因此会增加内存的消耗,而由此产生的I/O操作使缓存不那么有效。

微服务提供了只扩展那些需要扩展的服务的灵活性,它允许对资源的最优利用。正如我们前文所述,当需要时,可以只扩展餐桌预订服务而不会影响任何其他组件。它还允许二维扩展,在这里我们能做到不但增加交易量,而且还增加使用缓存的数据量(平台扩展)。

开发团队可以专注于交付和提供新功能,而不用担心扩展性问题(产品扩展)。

正如我们先前所看到的,微服务可以帮助你扩展平台、人员和产品维度。在这里的人员扩展指的是,取决于微服务的具体开发和重点需要,扩大或缩小团队规模。

微服务开发使用REST式的web服务开发,REST的服务器端是无状态的,使得在这个意义上,它是可扩展的,这意味着服务器之间没有太多的通信,从而它可以水平扩展。在出故障时回滚版本

因为整体式应用程序是打包在相同的归档文件或包含在单个目录中的,所以这阻碍了代码的模块化部署。例如,很多人可能都曾遇到过由于一项功能的故障,致使整个版本延迟发布的痛苦。

要解决这种问题,微服务给我们提供仅回滚那些出故障的功能的灵活性。这是一种非常灵活和富有成效的方法。例如,假设你是在线购物门户开发团队的成员,想要开发一个基于微服务的应用程序。可以将你的应用程序基于不同的领域,如商品、付款、购物车等进行划分,并将所有这些组件都作为单独的程序包打包。一旦你已经分别部署所有这些软件包,这些都将作为单个组件,可以被单独开发、测试和部署,并调用微服务。

现在,让我们看看它是如何帮你解决问题的。假设在某个生产版本中发布新的功能、增强功能和bug修复后,你发现支付服务中有缺陷需要立即修复。由于你已经使用基于微服务的架构,可以仅回滚付款服务而不是回滚整个版本,如果你的应用程序架构允许,还可以只对微服务付款服务应用修补程序,而不会影响其他服务。这不仅允许你妥善处理故障,还有助于迅速向客户交付功能或修补程序。采用新技术时的问题

整体式应用程序主要是基于在项目或产品开发过程最初主要使用的技术而开发和加强的。这使得很难在开发的后期或在产品处于成熟的状态后(例如,几年后)引进新技术。此外,同一个项目中的不同模块依赖于同一个库的不同版本,使这更具挑战性。

技术在逐年进步。例如,你的系统可能会使用Java设计,几年后,因为业务需要或为了利用新技术的优势,你又想要使用Ruby on rails或NodeJS开发新的服务。整体式的现有应用程序将很难利用新技术。

这不只是代码级集成,还与测试和部署相关。虽然可以通过重新编写整个应用程序来采用一项新技术,但这要耗费大量时间并且具有很高的风险。

另一方面,由于微服务是基于组件开发和设计的,它给我们提供了在开发中使用无论是新技术还是旧技术的任何技术的灵活性。它并不限制你使用特定的技术,这给你提供了一种开发和工程活动的新范式。可以在任何时候使用Ruby on Rails、NodeJS或任何其他技术。

那么,它是如何实现的呢?嗯,非常简单。基于微服务的应用程序代码并不打包成一个单一的归档文件,也并不存储在单个目录中。每个微服务都有其自己的文件,并且单独部署。一个新服务可以在隔离的环境中开发,并可以没有任何技术问题地被测试和部署。正如你所知,微服务还拥有自己独立的进程,它服务于它的目标时不存在任何冲突,如共享紧密耦合的资源,并且进程也保持独立。

因为根据定义,微服务是小型、自包含的功能,所以它提供了低风险地尝试一项新技术的机会。而对整体式系统而言,绝对不能这样。

还可以把你的微服务作为开放源码软件对外提供,所以它可由其他人使用。因此,如果需要,它能够与封闭源码的专有服务进行交互,而使用整体式应用程序,是不可能这么做的。与敏捷实践的契合

使用敏捷实践开发整体式应用程序是没有问题的,而且这些应用程序正在被开发中。持续集成(Continuous Integration,CI)和持续部署(Continuous Deployment,CD)也可以使用,但是,问题是——它能有效地使用敏捷实践吗?让我们来研究以下几点:● 例如,当事件互相依赖的可能性很大,并可能有不同的场景时,

一个事件只有在它所依赖的事件都已完成后才能发生。● 随着代码量的增加,生成应用程序需要更多的时间。● 大型整体式应用程序要实现频繁部署是一项困难的任务。● 即使更新单个组件,也将不得不重新部署整个应用程序。● 重新部署可能导致已经运行的组件出问题,例如作业调度器可能

会更改,无论组件是否对它产生影响。● 如果单个更改的组件不能正常工作,或如果它需要更多的修正,

重新部署的风险可能会增加。● UI开发人员总是需要更多的重新部署,这对于整体式的大型应用

程序是相当危险和费时的。

前面的问题都可以通过微服务很容易地解决。例如,UI开发人员可能拥有他们自己的UI组件,这些组件能够单独地开发、构建、测试和部署。同样,其他的微服务也可能独立部署,并且因其自主的特点,降低了系统故障风险。它用于开发的另一个优势是,UI开发人员可以使用JSON对象和模拟Ajax调用来开发UI,这些能够以隔离的方式占用。开发完成后,开发人员可以使用实际的API并测试这些功能。总之,可以说,微服务开发是快捷的,它符合企业的增量需求。减轻开发工作量——可以做得更好

一般来说,大型整体式应用程序的代码是开发人员最难理解的,并且新开发人员需要相当长的时间,才能成为生产力。甚至把大型整体式应用程序加载到IDE中都是麻烦的,它会降低IDE的运行速度,使开发人员的生产力降低。

大型整体式应用程序中的更改很难实施,并花费更多的时间。这是由于有大量的代码库,并且,如果未恰当并彻底地执行影响分析,存在bug的风险会很高。因此,执行全面影响分析成为开发人员实施更改之前的先决条件。

在整体式应用中,随着时间的推移,当所有组件都捆绑在一起时,依赖关系就建立了。因此,随着代码更改量(修改后的代码的行数)的增加,与代码更改相关联的风险呈指数级上升。

当一个代码库非常庞大并且有100多个开发人员正在它上面工作时,因为前面提到的原因,建立产品和实现新功能变得很困难。你需要确保一切都到位,并且一切都协调一致。在这种情况下,精心设计和记录的API的帮助很大。

Netflix,一家互联网流媒体按需提供商,在让约100人开发他们的应用程序时遇到了问题。然后,他们使用云平台,并将其应用程序分解成单独的小块。这些最终成为了微服务。提高速度和灵活性以便部署团队独立的愿望导致微服务不断壮大。

微型组件被制作成松耦合的,这归功于API的公开,这些API可以被持续地集成和测试。借助微服务的连续发布周期,变化被控制得很小,开发人员可以迅速利用它们执行回归测试,然后复审一遍并修复最终发现的瑕疵,以减少部署的风险。这会获得更快的速度与较低的相关风险。

由于功能分离和单一责任原则,微服务使团队非常有成效。可以在网上找到大量的大型项目由人数很少,如八至十个开发人员的团队开发完成的实例。

开发人员对于更少量的代码可以更集中注意力,由此产生的功能的更好实现,导致与产品的用户有更高的移情关系。这有助于功能的实现有更好的动机和明确性。与用户的移情关系会产生一个较短的反馈回路,以及更好、更迅速确定优先次序的功能管道。较短反馈回路使得缺陷检测也更快。

每个微服务团队都独立地工作,而无须与更多的观众协调就可以实现新功能或想法。在微服务设计中,端点故障处理也很容易实现。

最近,在一次会议中,一个团队展示了他们是如何在10周内开发出一个具有超级类型(Uber-type)跟踪功能,并包括iOS和Android应用程序基于微服务的传输-跟踪的应用程序。一家大型咨询公司针对相同的应用程序为他的客户给出7个月的估计开发时间。它表明了微服务与敏捷方法和CI/CD的契合方式。微服务的构建管道

微服务也可以使用诸如Jenkins、TeamCity等流行的CI/CD工具建立和测试。它与整体式的应用程序的构建方式是非常相似的。在多个微服务中,每个微服务都被当作一个小型应用程序。

例如,一旦把代码提交到存储库(SCM)中,CI/CD工具就触发构建过程:● 清理代码● 代码编译● 执行单元测试● 建立应用程序归档文件● 在开发、QA等各种服务器上部署● 执行功能和集成测试● 创建映像容器● 任何其他步骤

然后,更改pom.xml(在Maven的情况下)中的快照(SNAPSHOT)或发行(RELEASE)版本的版本构建触发器,会构建工件,如同在正常构建触发器中所述的那样。将工件发布到artifacts存储库。在存储库中标记此版本。如果你使用容器映像,那么就会生成容器映像。使用诸如Docker的容器部署

由于微服务的设计,需要有一个提供灵活性、敏捷性和平滑度的环境,以支持持续集成和部署,以及发布。微服务部署需要速度、隔离管理和敏捷的生命周期。

产品和软件也可以使用多式联运集装箱(intermodal-container)模型的概念来发布。多式联运集装箱是一个大型的标准化容器,用来执行多式联运货物运输。它允许货物使用各种交通工具——卡车、铁路或轮船运输,而不需要卸载并重新加载。这是储存和运输货物有效和安全的方式。它解决了航运的一个难题,这以前一直是一个耗时的劳动密集型过程,而重复的处理往往会打破易碎物品。

航运集装箱封装它们的内容。同样,软件容器也开始用于封装它们的内容(产品、应用程序、依赖关系,等等)。

以前,虚拟机(virtual machine,VM)被用于创建可以在需要的地方部署的软件映像。后来,诸如Docker的容器变得更受欢迎,因为它们同时与传统虚拟站系统和云环境兼容。例如,在开发人员的笔记本电脑上部署超过两个VM不太现实。建立和启动一个VM机器通常是I/O密集型的操作,因此也相当缓慢。

容器

容器(例如,Linux容器)提供轻量级运行时环境,该环境由虚拟机的核心功能和操作系统的隔离服务组成。这使得包装和执行微服务变得简单和顺利。

如下图所示,容器作为应用程序(微服务)在操作系统中运行。操作系统位于硬件的顶部,每个操作系统都可以有多个容器,使用一个容器运行应用程序。容器的层次关系图

容器能利用操作系统的内核接口,如cname和命名空间,它们允许共享相同内核的多个容器可以完全互相隔离地同时运行。这具有无须为每个用途而完成一个OS安装的好处,从而可以消除开销。这也使得硬件得到最佳的利用。

Docker

容器技术是当今发展最迅速的技术之一,而Docker引领这一技术。Docker是一个开放源码项目,2013年发布。2013年8月其交互式教程推出后,有1万个开发人员尝试使用它。1.0版本在2013年6月发布的时候,被下载了275万次。许多大公司,如微软、RedHat、惠普、OpenStack,以及诸如亚马逊网络服务、IBM和谷歌等服务提供商,都已与Docker签署了伙伴关系协定。

正如我们刚才提到的,Docker也利用了Linux内核的功能,例如cgroups和命名空间,以确保资源隔离,并把应用程序及其依赖项打包在一起。这种依赖项的包装使应用程序能够跨不同Linux操作系统/发行版本正常运行,从而实现可移植性级别的支持。此外,这种可移植性允许开发人员用任何一种语言开发一个应用程序,然后轻松地把它从笔记本电脑部署到测试或生产服务器上。Docker可原生地在Linux上运行。然而,利用VirtualBox和boot2docker,Docker也可以运行在Windows和Mac OS上。

容器仅由应用程序及其依赖项组成,依赖项包括基本的操作系统。这使得它轻量,并在资源利用率方面保持高效。开发人员和系统管理员对容器的可移植性和资源的有效利用感兴趣。

Docker容器中的所有程序都可原生地在主机上执行,并直接使用主机内核。每个容器都具有其自己的用户命名空间。

Docker的架构

如Docker文档指出的,Docker架构使用客户机-服务器架构。如下面的图例所示(源自Docker的网站),Docker客户端主要是由最终用户使用的用户界面,客户端与Docker守护进程之间往复通信。Docker守护程序承担构建、运行和分发你的Docker容器的繁重任务。Docker客户端和守护进程既可以在同一个系统中,也可以在不同的机器上运行。Docker客户端与守护进程通过套接字或通过基于REST的API进行通信。Docker寄存处是公共或私有Docker映像存储库,你可以从中上传或下载映像,例如Docker枢纽(hub.docker.com)就是一个公共的Docker寄存处。Docker的架构

Docker的主要组件是一个Docker映像和一个Docker容器。

Docker映像

Docker映像是一个只读的模板。例如,映像可以包含安装了Apache web服务器和web应用程序的Ubuntu操作系统。Docker映像是Docker生成组件。映像用于创建Docker容器。Docker提供简单的方式来生成新的映像或更新现有的映像。你还可以使用由其他人创建的映像。

Docker容器

Docker容器是从某个Docker映像创建的。Docker的工作是使得容器只能看到它自己的进程,并有分层到主机文件系统和网络栈的自己的文件系统,它通过管道连接到主机网络栈。Docker容器可以被运行、启动、停止、移动或删除。

部署

使用Docker部署的微服务处理三个部分的问题:1. 应用程序打包,例如jar2. 使用jar和依赖文件,包含Docker指令文件、Docker文件和命令docker build来构建Docker映像。这有助于反复创建映像。3. 使用docker run命令从新构建的映像执行Docker容器。

上述信息将帮助你了解Docker的基础知识。在第5章部署和测试,你将学习到更多关于Docker实际应用的知识。来源和参考资料:https://docs.docker.com。小结

在这一章,你已经学会或者演练了从传统整体式应用程序到微服务应用程序的大型软件项目高层次设计。你也了解了微服务简史、整体式应用程序的限制和好处,及微服务提供的灵活性。我希望这一章能帮助你理解整体式应用程序在生产环境中面临的共同问题,而微服务可以解决这些问题。你还了解了轻量级和高效的Docker容器,并看到容器化为何是一种很好的部署微服务的典型方法。

在下一章中,你会学习使用IDE和其他开发工具,针对不同的库来设置开发环境的相关知识。我们将面对创建基本项目和设置Spring Boot配置,建立和开发我们第一个微服务。在这里,我们将采用Java 8作为开发语言,并把Spring Boot用于我们的项目。2 设置开发环境

本章着重介绍开发环境的设置和配置。如果你熟悉这些工具和库,那么你可以跳过这一章,继续阅读第3章,在第3章你可以研究领域驱动设计的课题。

这一章将涵盖以下主题:● Spring Boot配置● 示例REST程序● 生成安装程序● 使用Postman Chrome扩展执行REST API测试● NetBeans——安装和设置

本书将仅使用开放源代码工具和框架来举例和编码,也将使用Java 8作为其编程语言,而应用程序框架将基于Spring框架。本书使用Spring Boot来开发微服务。

NetBeans提供最先进的、同时支持Java和JavaScript的集成开发环境(NetBeans Integrated Development Environment,IDE),足以满足我们的需求。它多年来演变了很多,并已内置支持大多数本书使用的技术,如Maven、Spring Boot等。因此,建议你使用NetBeans IDE。然而,你可以随意使用任何IDE。

我们将使用Spring Boot来开发REST服务和微服务。在本书中选择最流行的Spring框架——Spring Boot或其子集Spring Cloud是有意为之。因为这样我们就不需要从头开始编写应用程序,该框架对云应用程序大部分的东西都提供默认的配置。在Spring Boot配置一节中,我们对Spring Boot做了概述。如果你是Spring Boot初学者,那么这会对你有帮助。

我们将使用Maven作为我们的构建工具。与IDE的情况一样,可以随意使用任何构建工具,例如Gradle或Ant,我们将使用嵌入式的Jetty作为web服务器,但另一种选择是使用嵌入式的Tomcat web服务器。我们还将使用Chrome的Postman扩展来测试REST服务。

我们将从Spring Boot配置开始介绍。如果你是NetBeans初学者或者正面临设置环境的问题,可以参考最后一节NetBeans IDE安装部分的解释,否则完全可以跳过该节。Spring Boot配置

为了开发最先进且可用于生产的特定于Spring的应用程序,Spring Boot是一个明显的选择。其网站还说明了其真正的优势:“需要坚持构建可用于生产的Spring应用程序的观念。Spring Boot约定优先于配置,并且让你尽可能快地启动并运行。”Spring Boot概述

Spring Boot是Pivotal创建的优异的Spring工具,它于2014年4月发布(GA)。它基于SPR-9888(https://jira.spring.io/browse/SPR-9888)的请求被开发出来,该请求标题为“对无容器web应用程序架构的改进支持”。

你一定会想,为什么是无容器呢?因为,今天的云环境或PaaS都提供基于容器web架构的大多数功能,如可靠性、可管理性或可扩展性。因此,Spring Boot侧重于使其本身成为超轻量的容器。

Spring Boot预先配置使得开发可用于生产的web应用程序变得非常容易。Spring Initializer(初始值设定项)(http://start.spring.io)是一个网页,可以在其中选择构建工具如Maven或Gradle,还可以选择项目元数据,如组、工件和依赖项。当填充了所需的字段后,只需单击Generate Project(生成项目)按钮,它就会提供一个可以用于生产应用程序的Spring Boot项目。

在此页上,默认打包选项是jar。我们也会在微服务开发中使用jar包装。原因非常简单:它使得微服务的开发更容易。只要想想,管理和创建每个微服务都运行在其自己的服务器实例上的基础设施会多么困难,就明白了。

Josh Long在某个Spring IOs的谈话中分享了他的观点:“最好生成Jar,而不是War。”

稍后,我们将使用Spring Cloud,它是在Spring Boot之上的一个包装。把Spring Boot添加至REST示例

在编写本书的时候,Spring Boot提供了1.2.5发布版本,你可以使用最新的发布版本。Spring Boot使用Spring 4(4.1.7版本)。

打开pom.xml(可以从restsample | Project Files(项目文件)下找到),把Spring Boot添加到REST示例项目中: 4.0.0 com.packtpub.mmj restsample 1.0-SNAPSHOT jar org.springframework.boot spring-boot-starter-parent 1.2.5.RELEASE UTF-8 1.2.5.RELEASE org.springframework.boot spring-boot-starter-web ${spring-boot-version}

如果你是第一次添加这些依赖项,需要在如下所示的Projects窗格的restsample项目中通过鼠标右键单击Dependencies文件夹来下载依赖项。下载NetBeans的Maven依赖项

同样,要解决项目问题,用鼠标右键在NetBeans项目restsample上单击,并选择Resolve Project Problems…(解决项目问题),它将打开如下图所示的对话框。单击Resolve…按钮来解决问题。解决项目问题对话框如果在代理服务器后面使用Maven,那么需要更新\java\maven\conf\settings.xml中的代理服务器设置。可能需要重新启动NetBeans IDE才能使更新的设置生效。

如果在本地Maven存储库中未提供声明的依赖项和传递依赖项,那么前面的步骤将从远程Maven资源库中下载所有必需的依赖项。如果是第一次下载依赖项,那么可能需要花一些时间,这具体取决于你的Internet速度。添加一个嵌入式Jetty服务器

Spring Boot默认情况下提供Apache Tomcat作为嵌入式应用程序的容器。本书将在使用Apache Tomcat的地方使用嵌入式Jetty应用程序容器。因此,我们需要添加Jetty应用程序容器依赖项,以支持Jetty web服务器。

Jetty还允许使用classpath(类路径)读取密钥或信任存储区,也就是说,不需要把这些存储在JAR文件外面。如果使用具有SSL的Tomcat,那么将需要直接从文件系统访问密钥存储区或信任存储区,但不能使用类路径做这项工作。其结果是无法读取JAR文件中的密钥存储区或信任存储区,因为Tomcat要求密钥存储区(和信任存储区,如果你正在使用它)是可以直接在文件系统上访问的。

此限制并不适用于Jetty,它允许读取JAR文件中的密钥或信任存储区: org.springframework.boot spring-boot-starter-web org.springframework.bootspring-boot-starter-tomcat org.springframework.bootspring-boot-starter-jetty示例REST程序

我们将使用一个简单的方法来建立一个独立的应用程序。我们把这一切都打包成一个由main()方法驱动的单独的可执行JAR文件。在此过程中,使用Spring对嵌入Jetty servlet容器的支持作为HTTP运行时环境,而不是将它部署到一个外部的实例中。因此,我们将创建可执行的JAR文件来代替需要在外部web服务器上部署的WAR文件。

现在,当你在NetBeans IDE中准备好Spring Boot后,就可以创建你的示例web服务了。你将创建一个数学API,它可以执行简单的计算并生成JSON格式的结果。

下面让我们讨论一下如何调用REST服务并获取其响应。

此服务将处理对/calculation/sqrt或/calculation/power等的GET请求。GET请求应该返回200 OK响应,以及在正文中表示给定数字的平方根的JSON。它看起来应该像下面这样:{ "function": "sqrt", "input": [ "144" ], "output": [ "12.0" ]}

input字段是用于平方根函数的输入参数,而内容是结果的文本表示形式。

可以采用普通旧式Java对象(Plain Old Java Object,POJO)创建一个资源表示类对表示法进行建模,这个资源表示类使用包含字段、构造函数、setter和getter的普通旧式Java对象Plain Old Java Object(POJO),用于输入、输出和函数的数据。用它来对表示法进行建模:package com.packtpub.mmj.restsample.model;import java.util.List;public class Calculation { String function; private List input; private List output; public Calculation(List input, List output, Stringfunction) { this.function = function; this.input = input; this.output = output; } public List getInput() { return input; } public void setInput(List input) { this.input = input; } public List getOutput() { return output; } public void setOutput(List output) { this.output = output; } public String getFunction() { return function; } public void setFunction(String function) { this.function = function; }}编写REST控制器类

Roy Fielding在其博士论文中提出并定义了术语REST(Representational State Transfer,具象状态转换)。REST是一种用于诸如WWW的分布式超媒体系统的软件架构风格,RESTful(REST式)是指那些符合REST架构属性、原则和约束的系统。

现在,你将创建REST控制器来处理计算资源。在Spring REST式的web服务实现中,控制器负责处理HTTP请求。

@RestController

@RestController是Spring 4中引入的用于resource类的类级注解。它是@Controller与@ResponseBody的组合,因此类返回一个域对象,而不是视图。

在以下代码中,可以看到CalculationController类通过返回calculation类的一个新实例来处理对/calculation的GET请求。

我们将实现两个计算资源的URL——将平方根(Math.sqrt())函数实现为/calculation/sqrtURL,以及将幂(Math.pow())函数实现为/calculation/powerURL。

@RequestMapping

@RequestMapping注解在类级别使用,它将/calculation URI映射到CalculationController类,它确保对/calculation的HTTP请求被映射到CalculationController类。基于使用URI的注解@RequestMapping定义的路径(/calculation后缀,例如/calculation/sqrt/144),会映射到各自的方法。在这里,映射到/calculation/sqrt的请求被映射到sqrt()方法,而映射到/calculation/power的请求被映射到pow()方法。

你可能也已观察到我们并没有定义这些方法会使用什么请求方法(GET/POST/PUT等等)。@RequestMapping注解默认映射所有的HTTP请求方法。可以通过使用RequestMapping的方法属性来使用特定的方法。例如,可以通过以下方式使用POST方法来编写@RequestMethod注解@RequestMapping(value = "/power", method = POST)

为传递过程中的参数,此示例说明请求参数和路径参数都分别使用@RequestParamand和@PathVariable注解。

@RequestParam

@RequestParam负责将查询参数绑定到控制器方法的参数。例如,QueryParam底数和指数分别绑定到CalculationController的pow()方法的参数b和参数e上。pow()方法的两个查询参数都是必需的,因为我们未对它们使用任何默认值。可以使用@RequestParam的defaultValue属性来设置查询参数的默认值,例如@RequestParam (value="base",defaultValue="2"),在这里,如果用户未传递查询参数底数,那么底数将使用默认值2。

如果没有定义defaultValue,并且用户未提供请求的参数,则RestController返回HTTP状态代码400,以及400所需的字符串参数底数不存在(Required String parameter base is not present)的消息。如果缺少多个请求参数中的一个,它总是使用所需的第一个参数的引用:{ "timestamp": 1464678493402, "status": 400, "error": "Bad Request", "exception": "org.springframework.web.bind.MissingServletRequestParameterException", "message": "Required String parameter 'base' is not present", "path": "/calculation/power/"}

@PathVariable

@PathVariable可以帮助你创建动态的URI。@PathVariable注解允许你将Java参数映射到一个路径参数。它与@RequestMapping配合工作,其中后者在URI中创建占位符,然后要么作为PathVariable,要么作为方法的参数使用相同的占位符名称,正如可以在CalculationController类方法sqrt()中看到的。在这里,值占位符是在@RequestMapping内创建的,并且相同的值被赋予@PathVariable的值。

sqrt()方法提取URI中的参数来代替请求的参数。例如,http://localhost:8080/calculation/sqrt/144。在这里,值144作为路径参数传递,而此URL应该返回144的算术平方根,也就是12。

为了使用现成的基本检查,我们使用正则表达式"^-?+\\d+\\.?+\\d*$"来只允许有效的数字作为参数。如果传递了非数值,那么每个方法都在JSON的输出键中添加一条错误消息。CalculationController也使用正则表达式,在path变量(path参数)中的.+允许/path/{variable:.+}的数值中带小数点(.)。Spring将忽略最后一个点号后面的任何东西。Spring的默认行为把它当作文件扩展名。

还有其他替代办法,如在末尾添加一个正斜杠(/path/{variable}/)或通过把useRegisteredSuffixPatternMatch设置为true,使用PathMatchConfigurer(在Spring 4.0.1及更高版本中可用)重写WebMvcConfigurerAdapter的configurePathMatch()方法。package com.packtpub.mmj.restsample.resources;package com.packtpub.mmj.restsample.resources;import com.packtpub.mmj.restsample.model.Calculation;import java.util.ArrayList;import java.util.List;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import static org.springframework.web.bind.annotation.RequestMethod.GET;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/calculation")public class CalculationController { private static final String PATTERN = "^-?+\\d+\\.?+\\d*$"; @RequestMapping("/power") public Calculation pow(@RequestParam(value = "base") String b, @RequestParam(value = "exponent") String e) { List input = new ArrayList(); input.add(b); input.add(e); List output = new ArrayList(); String powValue = ""; if (b != null && e != null && b.matches(PATTERN) && e.matches(PATTERN)) { powValue = String.valueOf(Math.pow(Double.valueOf(b), Double.valueOf(e))); } else { powValue = "Base or/and Exponent is/are not set to numeric value."; } output.add(powValue); return new Calculation(input, output, "power"); } @RequestMapping(value = "/sqrt/{value:.+}", method = GET) public Calculation sqrt(@PathVariable(value = "value") String aValue){ List input = new ArrayList(); input.add(aValue); List output = new ArrayList(); String sqrtValue = ""; if (aValue != null && aValue.matches(PATTERN)) { sqrtValue = String.valueOf(Math.sqrt(Double.valueOf(aValue))); } else { sqrtValue = "Input value is not set to numeric value."; } output.add(sqrtValue); return new Calculation(input, output, "sqrt"); }}

在这里,我们只使用URI/calculation/power和/calculation/sqrt来公开Calculation资源的power和sqrt函数。在这里,我们使用sqrt和power作为我们URI的一部分,仅用于演示目的。理想情况下,这些应该已经被作为请求参数"function"的值来传递,或基于端点设计形成的类似东西。

一个有趣的事情是,由于Spring的HTTP消息转换器的支持,Calculation对象被自动转换为JSON,不需要手动执行此转换。如果Jackson 2位于类路径中,那么Spring的MappingJackson2HttpMessageConverter就会把Calculation对象转换为JSON。制作一个示例REST可执行应用程序

创建一个类RestSampleApp和SpringBootApplication注解。main()方法使用Spring Boot的SpringApplication.run()方法来启动应用程序。

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

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载