微服务架构 - 快速指南
微服务架构 - 简介
微服务是一种基于服务的应用程序开发方法。在这种方法中,大型应用程序将被划分为最小的独立服务单元。微服务是通过将整个应用程序划分为互连服务的集合来实现面向服务的架构(SOA)的过程,其中每个服务仅服务于一个业务需求。
走向微观的概念
在面向服务的架构中,整个软件包将被细分为小的、互连的业务单元。每个小型业务部门都将使用不同的协议相互通信,以便为客户提供成功的业务。现在的问题是,微服务架构(MSA)与 SOA 有何不同?简而言之,SOA是一种设计模式,微服务是一种实现SOA的实现方法论,或者说微服务是SOA的一种。
以下是我们在开发面向微服务的应用程序时需要牢记的一些规则。
独立- 每个微服务应该是独立部署的。
耦合- 所有微服务应彼此松散耦合,以便其中一个微服务的更改不会影响另一个微服务。
业务目标- 整个应用程序的每个服务单元应该是最小的,并且能够实现一个特定的业务目标。
让我们考虑一个在线购物门户的例子来深入了解微服务。现在,我们把整个电商门户分解为用户管理、订单管理、签到、支付管理、配送管理等小业务单元。一个成功的订单需要在特定的时间内走完所有这些模块。框架。以下是与一个电子商务系统关联的不同业务部门的综合图像。
每个业务模块都应该有自己的业务逻辑和利益相关者。它们出于某些特定需求与其他第三方供应商软件进行通信,并且彼此之间也进行通信。例如,订单管理可以与用户管理通信以获取用户信息。
现在,考虑到您正在运行一个包含前面提到的所有这些业务部门的在线购物门户,您确实需要一些由不同层(例如前端、后端、数据库等)组成的企业级应用程序。如果您的应用程序未扩展并且完全在一个war文件中开发,那么它将被称为典型的单体应用程序。根据 IBM 的说法,典型的单体应用程序内部应具有以下模块结构,其中只有一个端点或应用程序负责处理所有用户请求。
在上图中,您可以看到不同的模块,例如用于存储不同用户和业务数据的数据库。在前端,我们有不同的设备,通常在其中呈现用户或业务数据以供使用。在中间,我们有一个包,它可以是可部署的 EAR 或 WAR 文件,它接受来自用户端的请求,在资源的帮助下处理它,并将其返回给用户。一切都会好起来的,直到业务需要对上述示例进行任何更改为止。
考虑以下场景,您必须根据业务需求更改应用程序。
业务部门需要对“搜索”模块进行一些更改。然后,您需要更改整个搜索流程并重新部署您的应用程序。在这种情况下,您将重新部署其他单位,而无需进行任何更改。
现在,您的业务部门再次需要对“结帐”模块进行一些更改以包含“钱包”选项。您现在必须更改“签出”模块并将其重新部署到服务器中。请注意,您正在重新部署软件包的不同模块,而我们尚未对其进行任何更改。这里引入了面向服务架构的概念,更具体地说是微服务架构。我们可以以这样的方式开发我们的整体应用程序,即软件的每个模块都将表现为一个独立的单元,能够独立处理单个业务任务。
考虑以下示例。
在上述架构中,我们没有创建任何具有紧凑端到端服务的ear文件。相反,我们通过将软件的不同部分公开为服务来划分它们。软件的任何部分都可以通过使用各自的服务轻松地相互通信。这就是微服务在现代 Web 应用程序中发挥重要作用的方式。
让我们比较一下微服务中的购物车示例。我们可以将购物车分解为不同的模块,例如“搜索”、“过滤”、“结账”、“购物车”、“推荐”等。如果我们想构建一个购物车门户,那么我们必须构建上述模块之间可以相互连接,为您提供 24x7 良好的购物体验。
优点缺点
以下是有关使用微服务而不是使用单体应用程序的优点的一些要点。
优点
体积小- 微服务是 SOA 设计模式的实现。建议尽可能保留您的服务。基本上,一项服务不应执行多个业务任务,因此它的大小显然比任何其他单体应用程序小且易于维护。
专注- 如前所述,每个微服务都旨在仅交付一项业务任务。在设计微服务时,架构师应该关注服务的焦点,即它的可交付成果。根据定义,一个微服务本质上应该是全栈的,并且应该致力于仅提供一种业务属性。
自治- 每个微服务应该是整个应用程序的自治业务单元。因此,应用程序变得更加松散耦合,这有助于降低维护成本。
技术异构性- 微服务支持不同技术在一个业务单元中相互通信,这有助于开发人员在正确的地方使用正确的技术。通过实施异构系统,可以获得最大的安全性、速度和可扩展的系统。
弹性- 弹性是隔离软件单元的属性。微服务在构建方法中遵循高水平的弹性,因此每当一个单元发生故障时,它不会影响整个业务。弹性是实现高度可扩展且耦合度较低的系统的另一个属性。
易于部署- 由于整个应用程序被细分为小块单元,因此每个组件本质上都应该是完整的堆栈。与其他同类的整体应用程序不同,所有这些都可以非常轻松地部署在任何环境中,并且时间复杂度较低。
以下是微服务架构的一些缺点。
缺点
分布式系统- 由于技术异构性,将使用不同的技术来开发微服务的不同部分。需要大量熟练的专业人员来支持这个大型异构分布式软件。因此,分布式和异构性是使用微服务的首要缺点。
成本- 微服务成本高昂,因为您必须为不同的业务任务维护不同的服务器空间。
企业准备就绪- 微服务架构可以被视为不同技术的组合,因为技术正在日益发展。因此,要让微服务应用企业能够与传统的软件开发模式进行比较是相当困难的。
基于 SOA 的微服务
下表列出了 SOA 和微服务的某些特性,凸显了使用微服务相对于 SOA 的重要性。
成分 | 面向服务架构 | 微服务 |
---|---|---|
设计模式 | SOA 是计算机软件的一种设计范例,其中软件组件以服务的形式暴露给外部世界以供使用。 | 微服务是SOA的一部分。它是SOA 的专门实现。 |
依赖性 | 业务部门相互依赖。 | 所有业务单元都是相互独立的。 |
尺寸 | 软件体积比传统软件大。 | 软件体积小。 |
技术 | 技术栈比微服务少。 | 微服务本质上是异构的,因为使用精确的技术来执行特定的任务。微服务可以被视为多种技术的集合。 |
自主和专注 | SOA 应用程序旨在执行多种业务任务。 | 微服务应用程序旨在执行单个业务任务。 |
自然 | 本质上是整体的。 | 本质上是全栈。 |
部署 | 部署非常耗时。 | 部署非常简单。因此,耗时会更少。 |
成本效益 | 更具成本效益。 | 性价比较低。 |
可扩展性 | 与微服务相比更少。 | 完全缩放。 |
例子 | 让我们考虑一个在线 CAB 预订应用程序。如果我们想使用 SOA 构建该应用程序,那么它的软件单元将是 -
|
如果使用微服务架构构建相同的应用程序,那么它的 API 将是 -
|
微服务架构 - 扩展
扩展是将软件分解为不同单元的过程。缩放还定义了可扩展性。可扩展性是实现应用程序更高级功能的潜力。它有助于提高应用程序的安全性、耐用性和可维护性。我们在行业中遵循三种类型的扩展程序。以下是不同的缩放方法以及相应的现实示例。
X 轴缩放
X 轴缩放也称为水平缩放。在此过程中,整个应用程序被细分为不同的水平部分。通常,任何 Web 服务器应用程序都可以具有这种类型的扩展。考虑一个遵循水平扩展的普通 MVC 架构,如下图所示。
作为一个例子,我们可以考虑任何 JSP servlet 应用程序。在此应用程序中,控制器控制每个请求,并在必要时通过与模型通信来生成视图。通常,单片应用程序遵循这种扩展方法。X 轴缩放本质上是非常基本的,并且耗时非常少。在这种方法中,一个软件将根据该单元负责的不同任务进行扩展。例如,控制器负责控制传入和传出请求,视图负责在浏览器中向用户表示业务功能,而模型负责存储我们的数据,它充当数据库。
Y 轴缩放
Y 轴缩放也称为垂直缩放,包括任何资源级别缩放。任何 DBaaS 或 Hadoop 系统都可以被认为是 Y 轴缩放的。在这种类型的扩展中,通过实现某些逻辑来重定向和限制用户请求。
让我们以 Facebook 为例。Facebook每秒需要处理179万用户;因此,控制流量是 Facebook 网络工程师的一项巨大责任。为了克服任何危险,他们遵循 Y 轴扩展,其中包括同时运行具有相同应用程序的多个服务器。现在,为了控制如此巨大的流量,Facebook 将所有流量从一个区域重定向到特定服务器,如图所示。这种基于区域的流量转移在架构语言中称为负载均衡。
这种将资源分解为小的独立业务单元的方法称为 Y 轴扩展。
Z 轴缩放
X 轴和 Y 轴缩放更容易理解。然而,一个应用程序也可以在业务层面进行扩展,这称为Z轴扩展。以下是在不同垂直业务部门扩展出租车服务应用程序的示例。
扩展的优点
成本- 软件的适当扩展将降低维护成本。
性能- 由于松散耦合,适当缩放的软件的性能始终优于未缩放的软件。
负载分布- 使用不同的技术,我们可以轻松维护服务器负载。
重用- 软件的可扩展性也提高了软件的可用性。
微服务架构 - 蓝图
微服务在内部实现了SOA。从更广泛的意义上讲,我们可以将其视为一个 SOA 应用程序的子集。
规则和工作流程
以下是开发微服务时需要注意的原则。
高内聚- 所有业务模型都需要尽可能细分为最小的业务部分。每项服务应该只专注于执行一项业务任务。
独立- 所有服务本质上应该是全栈并且彼此独立。
以业务领域为中心- 软件将根据业务部门进行模块化,而不是基于层级的。
自动化- 测试部署将自动化。尝试引入最少的人际互动。
可观察- 每个服务本质上都是全栈的,它们应该像企业应用程序一样独立部署和观察。
团队管理
“两个披萨规则”是一种限制微服务开发团队的参与者数量的规则。根据这一规则,一个应用程序的团队成员数量应该足够少,以至于可以吃两个披萨。一般情况下,数量不应超过8个。由于微服务本质上是全栈,因此团队本质上也是全栈。为了提高生产力,我们需要建立一支最多 8 名成员的团队,并拥有该服务所需的各种专业知识。
任务管理
任务在软件开发生命周期中扮演着重要角色。开发大型应用程序可以分解为几个小的任务单元。让我们考虑一下我们需要开发一个应用程序,例如 Facebook。那么,“登录”功能可以被视为整个构建过程的一个任务。每项任务的进展都需要在高技能专业人员的监督下进行适当的监控。敏捷是业界众所周知的流程结构,用于跟上良好的任务管理。
不同的元素
到现在为止我们已经了解了什么是微服务以及它在现代MVC架构之上的基本需求是什么。在本章中,我们将学习该架构中对于服务同样重要的不同元素。
服务类别
通过微服务这个名字,我们假设它将是一个可以通过 HTTP 协议使用的服务,但是我们需要知道使用这种架构可以构建什么样的服务。以下是可以使用微服务架构实现的服务列表。
平台即服务[PaaS] - 在这种面向服务的架构中,平台作为一种工具提供,可以根据业务需求进行定制。PaaS 在移动应用程序开发中发挥着重要作用。PaaS 最好的例子是 Google App Engine,Google 提供了不同的有用平台来构建您的应用程序。PaaS最初的开发目的是为开发人员提供内置的架构或基础设施。它在显着缩短的时间内降低了更高级别的编程复杂性。以下是 Google 提供的 PaaS 的快照。
软件即服务 [SaaS] - 软件即服务是一种软件许可业务,其中软件集中托管并在订阅的基础上获得许可。SaaS 主要通过浏览器访问,是人力资源管理 (HRM)、企业资源规划 (ERP)、客户关系管理 (CRM) 等许多垂直行业中非常常见的架构模式。下面的屏幕截图显示了以下示例: Oracle 提供的不同 SaaS。
基础设施即服务 [IaaS] - 基础设施在 IT 行业中发挥着良好的作用。一些组织使用云计算提供虚拟基础设施作为其服务。IaaS对于在软件开发中带来敏捷性、成本效益、安全性、性能、生产力等非常有帮助。Amazon EC2 和 Microsoft Azure 是 IaaS 的最大例子。下图描述了 AWS 的示例,其中数据中心作为 IaaS 提供。
数据即服务 [DaaS] - 信息技术处理数据,一些顶级行业领导者相信数据将成为社会的新生计。DaaS 是一种与企业集团共享数据以进行研究和分析的服务。DaaS 为数据访问层带来了简单性、敏捷性和安全性。以下是 Oracle 数据云的示例,您可以根据自己的业务需求对其进行访问或许可。
后端即服务 [BaaS] - BaaS 也称为 MBaaS,意思是移动后端即服务。在这种类型的服务中,应用程序的后端将提供给业务部门以供其自己的企业使用。所有推送通知、社交网络服务都属于此类服务。Facebook 和 Twitter 是著名的 BaaS 服务提供商的例子。
安全
在处理大量客户数据时,安全性起着重要作用。安全问题与市场上提供的各种服务相关。无论您使用什么云——私有云、公共云、混合云等,都应该在各个级别上维护安全性。整个安全问题可以大致分为以下部分 -
服务提供商面临的安全问题- 此类安全问题是谷歌、亚马逊等服务提供商面临的。为了确保安全保护,需要对客户端进行背景调查,尤其是那些直接访问核心部分的客户端云端。
消费者面临的安全问题- 云成本低廉,因此在各行业得到广泛应用。一些组织将用户详细信息存储在第三方数据中心,并在需要时提取数据。因此,必须保持安全级别,以便一个客户的任何私人数据都不应该对任何其他用户可见。
为了防止上述安全问题,以下是组织使用的一些防御机制。
威慑控制- 了解潜在威胁以减少网络攻击。
预防控制- 维护高级别的身份验证策略来访问您的云。
侦探控制- 监视您的用户并检测任何潜在风险。
纠正控制- 与不同团队密切合作,解决检测控制阶段出现的问题。
构图模式
软件组合意味着构建软件产品的方式。基本上,它涉及高级软件架构图,其中软件的不同模块将针对特定业务目标进行通信。在本章中,我们将了解组织中广泛使用的不同软件组合模式。在微服务中,我们将每个功能拆分为一个进程。这些服务中的每一项本质上都是独立且全栈的。
功能分解在构建微服务时发挥着重要作用。它为您的应用程序提供敏捷性、灵活性和可扩展性。
聚合器模式
聚合器模式是开发微服务时可以实现的最简单的 Web 模式。在这种组合模式中,一个简单的 Web 模块将充当负载均衡器,这意味着它将根据需求调用不同的服务。下图描述了具有聚合器设计的简单微服务 Web 应用程序。如下图所示,“聚合器”负责一一调用不同的服务。如果我们需要对服务 A、B 和 C 的结果应用任何业务逻辑,那么我们可以在聚合器本身中实现业务逻辑。
聚合器可以再次作为另一种服务暴露给外部世界,其他人可以在需要时使用它。在开发聚合器模式 Web 服务时,我们需要记住,每个服务 A、B 和 C 都应该有自己的缓存层,并且本质上应该是全栈。
代理模式
代理微服务模式是聚合器模型的变体。在这个模型中,我们将使用代理模块而不是聚合模块。代理服务可以单独调用不同的服务。
在代理模式中,我们可以通过提供转储代理层来构建一级额外的安全性。该层的作用类似于接口。
链式图案
顾名思义,这种构图模式将遵循链式结构。在这里,我们不会使用客户端和服务层之间的任何内容。相反,我们将允许客户端直接与服务进行通信,并且所有服务将以这样的方式链接起来,即一个服务的输出将成为下一个服务的输入。下图显示了典型的链式模式微服务。
这种架构的一个主要缺点是,客户端将被阻塞,直到整个过程完成。因此,强烈建议保持链条的长度尽可能短。
分支微服务模式
分支微服务是聚合器模式和链式模式的扩展版本。在这种设计模式中,客户端可以直接与服务进行通信。此外,一项服务一次可以与多个服务进行通信。以下是 Branch 微服务的图示。
分支微服务模式允许开发人员动态配置服务调用。所有服务调用都将以并发方式发生,这意味着服务 A 可以同时调用服务 B 和 C。
共享资源模式
共享资源模式实际上是前面提到的所有类型模式的组合。在此模式中,客户端或负载均衡器将在必要时直接与每个服务进行通信。这是大多数组织广泛遵循的最有效的设计模式。以下是共享资源设计模式的图示。
微服务架构 - SOA 实践
在本章中,我们将开发一个基于 SOA 架构的 CRUD 应用程序。在后面的章节中,我们会将这个服务分解为微服务,并了解SOA和微服务架构之间的基本区别。
系统配置和设置
在本节中,我们将构建一个示例 CRUD 应用程序,每当我们调用服务时,它将返回一个 JSON 对象作为响应。我们将使用 Jersey 框架来开发它。以下是设置本地系统环境的步骤。
开发 CRUD 应用程序
步骤 1 - 我们将使用 NetBeans 作为开发 IDE。请在 NetBeans 官方网站https://netbeans.org/downloads/上下载并安装最新版本。
步骤 2 - 打开 NetBeans IDE。转到“文件->新建项目”。弹出以下屏幕截图。选择“Maven”作为类别,然后选择“Project from ArchType”作为项目,然后单击“下一步”。
这将下载创建您的第一个 Maven 项目和 RESTful Web 服务所需的所有 jar 文件。
步骤 3 - 在上一步中点击“下一步”按钮后,将显示以下屏幕截图。在这里,您必须指定 Maven 原型。
在搜索框中,搜索“Jersey-archType-Webapp(2.16)”并选中“显示旧版本”复选框。
步骤 4 - 选择相同内容后,您将被重定向到以下屏幕。从列表中选择首选 jar,然后单击“下一步”继续。
步骤 5 - 在此步骤中,您需要提供项目名称及其组 ID 以及包详细信息。提供所有这些信息后,单击“完成”继续。
步骤 6 - 您已完成工作区设置。项目目录如下所示。
查看你的“Dependencies”文件夹,你会发现Maven已经自动下载了该项目所需的所有jar文件。
步骤 7 - 您的工作区已设置完毕,您可以开始编码。继续创建四个类和包,如下面的屏幕截图所示。您可以发现 MyResource.java 已经由 Maven 创建,因为 Maven 足够聪明,可以检测到您将要构建自己的 Web 服务。
步骤 8 - 完成上述步骤后,我们将构造 POJO 类 UserProfile.java,如下所示。
package com.tutorialspoint.userprofile.Model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class UserProfile { private long ProId; private String FName; private String LName; private String Add; public UserProfile(){} public UserProfile(long Proid, String Fname, String Lname,String Add) { this.ProId = Proid; this.FName = Fname; this.LName = Lname; this.Add = Add; } public long getProId() { return ProId; } public void setProId(long ProId) { this.ProId = ProId; } public String getFName() { return FName; } public void setFName(String FName) { this.FName = FName; } public String getLName() { return LName; } public void setLName(String LName) { this.LName = LName; } public String getAdd() { return Add; } public void setAdd(String Add) { this.Add = Add; } }
步骤 9 - 现在我们将创建数据库类。由于这是学习材料的一部分,我们不会使用任何 DB 作为我们的数据库。我们将使用内置的 Java 内存作为临时内存。正如您在下面的代码集中看到的,我们将使用 MAP 作为数据库。我们执行的所有 Web 服务操作都将在该类中定义的 MAP 上进行。
package com.tutorialspoint.userprofile.DAO; import com.tutorialspoint.userprofile.Model.UserProfile; import java.util.HashMap; import java.util.Map; public class DatabaseClass { private static Map<Long,UserProfile> messages = new HashMap<Long,UserProfile>(); public static Map<Long,UserProfile> getUsers() { return messages; // Each time this method will return entire map as an instance of database } }
步骤 10 - 现在让我们构建我们的服务类。继续将以下代码集复制粘贴到“ProfileService.java”类中。我们将在这个类中声明要向外部世界公开的所有 Web 服务方法。我们需要创建 DatabaseClass 的一个引用,以便可以在此类中访问我们的临时数据库。
package com.tutorialspoint.userprofile.service; import com.tutorialspoint.userprofile.DAO.DatabaseClass; import com.tutorialspoint.userprofile.Model.UserProfile; import java.util.ArrayList; import java.util.List; import java.util.Map; public class ProfileService { private Map<Long,UserProfile> Userprofiles = DatabaseClass.getUsers(); // Creating some predefine profile and populating the same in the map public ProfileService() { UserProfile m1 = new UserProfile(1L,"Tutorials1","Point1","TutorialsPoint.com"); UserProfile m2 = new UserProfile(2L,"Tutorials2","Point2","TutorialsPoint.com2"); UserProfile m3 = new UserProfile(3L,"Tutorials3","Point3","TutorialsPoint.com3"); UserProfile m4 = new UserProfile(4L,"Tutorials4","Point4","TutorialsPoint.com4"); Userprofiles.put(1L, m1); Userprofiles.put(2L, m2); Userprofiles.put(1L, m3); Userprofiles.put(2L, m4); } //Method to fetch all profile public List<UserProfile> getAllProfile() { List<UserProfile> list = new ArrayList<UserProfile>(Userprofiles.values()); return list; } // Method to fetch only one profile depending on the ID provided public UserProfile getProfile(long id) { return Userprofiles.get(id); } //Method to add profile public UserProfile addProfile(UserProfile UserProfile) { UserProfile.setProId(Userprofiles.size()+1); Userprofiles.put(UserProfile.getProId(), UserProfile); return UserProfile; } //method to update Profile public UserProfile UpdateProfile(UserProfile UserProfile) { if(UserProfile.getProId()<=0) { return null; } else { Userprofiles.put(UserProfile.getProId(), UserProfile); return UserProfile; } } //method to delete profile public void RemoveProfile(long Id) { Userprofiles.remove(Id); } }
步骤 11 - 在此步骤中,我们将创建与 URL 链接的资源类,并调用相应的服务。
package com.tutorialspoint.userprofile.Resource; import com.tutorialspoint.userprofile.Model.UserProfile; import com.tutorialspoint.userprofile.service.ProfileService; import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("/Profile") @Consumes(MediaType.APPLICATION_XML) @Produces(MediaType.APPLICATION_XML) public class ProfileResource { ProfileService messageService = new ProfileService(); @GET public List<UserProfile> getProfile() { return messageService.getAllProfile(); } @GET @Path("/{ProID}") public UserProfile getProfile(@PathParam("ProID")long Id) { return messageService.getProfile(Id); } @POST public UserProfile addProfile(UserProfile profile) { return messageService.addProfile(profile); } @PUT @Path("/{proID}") public UserProfile UpdateProfile(@PathParam("proID")long Id,UserProfile UserProfile) { UserProfile.setProId(Id); return messageService.UpdateProfile(UserProfile); } @DELETE @Path("/{ProID}") public void deleteProfile(@PathParam("ProID")long Id) { messageService.RemoveProfile(Id); } }
步骤 12 - 清理构建项目并运行它。如果一切顺利,那么您应该在访问http://localhost:8080/UserProfile/webapi/Profile” URL时在浏览器中获得以下输出。
您可以看到不同的条目是使用 XML 表示形式填充的。
通过应用正确的方法 URL,可以使用 Postman 测试不同的方法。
@GET 方法- 下面的屏幕截图演示了我们如何获得 get 请求所需的结果,该结果返回所有用户详细信息。
@POST - 以下请求可用于测试我们的 Post 方法。请注意 proId 是如何自动生成的。
@PUT - 此方法将更新条目。以下屏幕截图演示了 Jersey 如何从请求 URL 获取 proId 并更新相同的用户配置文件回复。
以同样的方式,您可以检查 Web 服务中是否有其他可用的方法。
在上一节中,我们开发了一项将公开 CRUD 功能的服务。现在,每当我们尝试在应用程序中实现此服务时,我们都需要创建此应用程序的客户端并将其附加到我们的应用程序。在本章中,我们将学习如何使用微服务的概念来构建此功能。以下是使用上述步骤构建的应用程序的图示。
演员应该是我们服务的入口点。在这种情况下,“ProfileResource.java”履行参与者的职责。该类会调用不同的方法来执行不同的操作,例如添加、更新和删除。
CRUD应用分解
根据微服务的主要原则,每个模块只需要一个业务任务,因此一个参与者不应该负责所有四个 CRUD 功能。考虑以下示例,我们在其中引入了一些新角色,以便您从概念上清楚地了解微服务是 SOA 的架构表示。
“主用户”是与“应用程序控制器”通信以满足自身需求的用户。“应用程序控制器”只是根据最终用户的请求调用不同的“资源管理器”。“资源管理器”完成需要完成的工作。让我们快速了解一下应用程序不同单元的不同角色。
最终用户/主要用户- 向应用程序控制器请求一些资源。
应用程序- 接收请求并将其转发到特定的资源管理器。
资源管理器- 执行更新、删除和添加用户的实际工作。
查看一个类的总责任如何在不同的其他类之间分配。
微服务架构 - MSA 实践
在本章中,我们将构建一个微服务应用程序,该应用程序将使用不同的可用服务。我们都知道,微服务并不是一种经济有效的构建应用程序的方式,因为我们构建的每个服务本质上都是全栈的。在本地环境中构建微服务需要高端系统配置,因为您需要有四个服务器实例来保持运行,以便可以在某个时间点使用它。为了构建我们的第一个微服务,我们将使用一些可用的 SOA 端点,并在我们的应用程序中使用相同的端点。
系统配置和设置
在进一步进入构建阶段之前,请相应地准备您的系统。您将需要一些公共网络服务。你可以很容易地用谷歌搜索这个。如果您想使用 SOAP Web 服务,那么您将获得一个 WSDL 文件,然后您需要从那里使用特定的 Web 服务。对于 REST 服务,您只需要一个链接即可使用该服务。在此示例中,您将在一个应用程序中加入三种不同的 Web 服务“SOAP”、“REST”和“自定义”。
应用架构
您将使用微服务实施计划创建一个 Java 应用程序。您将创建一个自定义服务,该服务的输出将作为其他服务的输入。
以下是开发微服务应用程序应遵循的步骤。
步骤 1:为 SOAP 服务创建客户端- 有许多免费的 Web API 可用于学习 Web 服务。出于本教程的目的,请使用“ http://www.webservicex.net/”的 GeoIP 服务。WSDL 文件在其网站“webservicex.net”上的以下链接中提供。要从此 WSDL 文件生成客户端,您所需要做的就是在终端中运行以下命令。
wsimport http://www.webservicex.net/geoipservice.asmx?WSDL
该命令将在名为“SEI”的文件夹下生成所有必需的客户端文件,该文件夹以服务端点接口命名。
步骤 2:创建自定义 Web 服务- 按照本教程前面阶段提到的相同流程,构建一个名为“CustomRest”的基于 Maven 的 REST api。完成后,您将找到一个名为“MyResource.java”的类。继续使用以下代码更新此类。
package com.tutorialspoint.customrest; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("myresource") public class MyResource { @GET @Produces(MediaType.TEXT_PLAIN) public String getIt() { return "IND|INDIA|27.7.65.215"; } }
一切完成后,继续在服务器上运行该应用程序。您应该在浏览器中得到以下输出。
这是Web服务器,一旦调用就会返回一个字符串对象。这是输入服务,提供可供其他应用程序使用以生成记录的输入。
步骤 3:配置另一个 Rest API - 在此步骤中,使用services.groupkt.com 上提供的另一个 Web 服务。调用时将返回一个 JSON 对象。
步骤 4:创建 JAVA 应用程序- 通过选择“新建项目”->“JAVA 项目”创建一个普通的 Java 应用程序,然后单击“完成”,如下面的屏幕截图所示。
步骤 5:添加 SOAP 客户端- 在步骤 1 中,您已经为 SOAP Web 服务创建了客户端文件。继续将这些客户端文件添加到您当前的项目中。成功添加客户端文件后,您的应用程序目录将如下所示。
第 6 步:创建主应用程序- 创建主类,您将在其中使用所有这三个 Web 服务。右键单击源项目并创建一个名为“MicroServiceInAction.java”的新类。下一个任务是从此调用不同的 Web 服务。
步骤 7:调用您的自定义 Web 服务- 为此,请继续添加以下代码集来实现调用您自己的服务。
try { url = new URL("http://localhost:8080/CustomRest/webapi/myresource"); conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Accept", "application/json"); if (conn.getResponseCode() != 200) { throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); } BufferedReader br = new BufferedReader(new InputStreamReader( (conn.getInputStream()))); while ((output = br.readLine()) != null) { inputToOtherService = output; } conn.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
步骤 8:使用 SOAP 服务- 您已经生成了客户端文件,但您不知道应该在整个包中调用哪个方法?为此,您需要再次引用用于生成客户端文件的 WSDL。每个 WSDL 文件都应该有一个“wsdl:service”标签搜索此标签。它应该是该 Web 服务的入口点。以下是该应用程序的服务端点。
现在您需要在您的应用程序中实现此服务。以下是实现 SOAP Web 服务所需的一组 Java 代码。
GeoIPService newGeoIPService = new GeoIPService(); GeoIPServiceSoap newGeoIPServiceSoap = newGeoIPService.getGeoIPServiceSoap(); GeoIP newGeoIP = newGeoIPServiceSoap.getGeoIP(Ipaddress); // Ipaddress is output of our own web service. System.out.println("Country Name from SOAP Webserivce ---"+newGeoIP.getCountryName());
步骤 9:使用 REST Web 服务- 到目前为止,其中两项服务已被使用。在此步骤中,将在您的自定义 Web 服务的帮助下使用另一个具有自定义 URL 的 REST Web 服务。使用以下代码集来执行此操作。
String url1="http://services.groupkt.com/country/get/iso3code/";//customizing the Url url1 = url1.concat(countryCode); try { URL url = new URL(url1); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Accept", "application/json"); if (conn.getResponseCode() != 200) { throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); } BufferedReader br = new BufferedReader(new InputStreamReader( (conn.getInputStream()))); while ((output = br.readLine()) != null) { System.out.println(output); } conn.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
步骤 10:使用所有服务- 考虑到您的“CustomRest”网络服务正在运行并且您已连接到互联网,如果一切都成功完成,那么以下应该是您的综合主类。
package microserviceinaction; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.StringTokenizer; import net.webservicex.GeoIP; import net.webservicex.GeoIPService; import net.webservicex.GeoIPServiceSoap; public class MicroServiceInAction { static URL url; static HttpURLConnection conn; static String output; static String inputToOtherService; static String countryCode; static String ipAddress; static String CountryName; public static void main(String[] args) { //consuming of your own web service try { url = new URL("http://localhost:8080/CustomRest/webapi/myresource"); conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Accept", "application/json"); if (conn.getResponseCode() != 200) { throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); } BufferedReader br = new BufferedReader(new InputStreamReader( (conn.getInputStream()))); while ((output = br.readLine()) != null) { inputToOtherService = output; } conn.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //Fetching IP address from the String and other information StringTokenizer st = new StringTokenizer(inputToOtherService); countryCode = st.nextToken("|"); CountryName = st.nextToken("|"); ipAddress = st.nextToken("|"); // Call to SOAP web service with output of your web service--- // getting the location of our given IP address String Ipaddress = ipAddress; GeoIPService newGeoIPService = new GeoIPService(); GeoIPServiceSoap newGeoIPServiceSoap = newGeoIPService.getGeoIPServiceSoap(); GeoIP newGeoIP = newGeoIPServiceSoap.getGeoIP(Ipaddress); System.out.println("Country Name from SOAP Webservice ---"+newGeoIP.getCountryName()); // Call to REST API --to get all the details of our country String url1 = "http://services.groupkt.com/country/get/iso3code/"; //customizing the Url url1 = url1.concat(countryCode); try { URL url = new URL(url1); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("Accept", "application/json"); if (conn.getResponseCode() != 200) { throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); } BufferedReader br = new BufferedReader(new InputStreamReader( (conn.getInputStream()))); while ((output = br.readLine()) != null) { System.out.println(output); } conn.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
运行此文件后,您将在控制台中看到以下输出。您已经成功开发了您的第一个微服务应用程序。