Microservice Architecture 简明教程
Microservice Architecture - Introduction
微服务是一种基于服务的应用程序开发方法。此方法中,大型应用程序将被划分为最小的独立服务单元。微服务是通过将整个应用程序划分为一系列相互关联的服务来实现面向服务架构(SOA)的过程,其中每个服务只满足一项业务需求。
The Concept of Going Micro
在面向服务架构中,整个软件包将被细分为小的、相互关联的业务单元。每个这些小的业务单元将使用不同的协议互相通信,以向客户交付成功的业务。现在的问题是,微服务架构(MSA)与 SOA 有什么不同?一句话来说,SOA 是一种设计模式,微服务是实现 SOA 的实现方法,或者我们可以说微服务是 SOA 的一种类型。
以下是开发以微服务为导向的应用程序时需要记住的一些规则。
-
Independent − 每个微服务都应该能够独立部署。
-
Coupling − 所有微服务都应该彼此松散耦合,这样其中一个发生变化时不会影响另一个。
-
Business Goal − 整个应用程序的每个服务单元都应该是最小的,并且能够实现一个特定的业务目标。
让我们考虑一个在线购物门户的例子,以深入了解微服务。现在让我们将整个电子商务门户分解为小型业务单元,例如用户管理、订单管理、入住、支付管理、配送管理等。一笔成功的订单需要在特定时间范围内历经所有这些模块。以下是与电子商务系统相关的不同业务单元的合并图像。
这些业务模块中的每一个都应该有自己的业务逻辑和利益相关者。它们与其他第三方供应商软件进行通信以满足某些特定需求,并且彼此之间也进行通信。例如,订单管理可能会与用户管理进行通信以获取用户信息。
现在,考虑到您正在运行包含前面提到的所有业务单元的在线购物门户,您确实需要一个由前端、后端、数据库等不同层组成的企业级应用程序。如果您的应用程序没有进行扩展并在一个单独的 war 文件中得到完全开发,那么它将被称为典型的单体应用程序。据 IBM 所述,典型的单体应用程序在内部应具有以下模块结构,其中只有一个端点或应用程序负责处理所有用户请求。
在上面的图像中,您可以看到用于存储不同用户和业务数据的不同模块,例如数据库。在前端,我们有不同的设备,我们通常在那里呈现用户或业务数据以供使用。在中间,我们有一个包可以是可部署的 EAR 或 WAR 文件,它接受用户末端的请求,借助于资源对其进行处理,然后将其呈现在用户面前。在业务需要对上述范例进行任何更改之前,一切都很好。
考虑以下情况,您必须根据业务需求更改应用程序。
业务单元需要对“搜索”模块进行一些更改。然后,您需要更改整个搜索过程并重新部署应用程序。在这种情况下,您正在重新部署其他单元而根本没有进行任何更改。
现在,您的业务部门需要对“签出”模块进行一些更改以包括“钱包”选项。您现在必须更改“签出”模块并将它重新部署到服务器中。请注意,您正在重新部署软件包的不同模块,而我们并没有对其进行任何更改。这就是面向服务的架构,更具体地说是微服务架构的概念的由来。我们可以以这种方式开发单体应用程序,使得软件的每个模块都充当独立的单元,能够独立地处理单个业务任务。
考虑以下示例。
在上述架构中,我们不会创建包含端到端紧凑服务的任何 ear 文件。相反,我们通过将它们作为服务公开来划分软件的不同部分。软件的任何部分都可以通过使用各自的服务来轻松地彼此进行通信。这就是微服务在现代 Web 应用程序中扮演重要角色的方式。
让我们在微服务的意义上比较我们的购物车示例。我们可以将购物车分解为不同的模块,例如“搜索”、“筛选”、“签出”、“购物车”、“推荐”等。如果我们想构建一个购物车门户,那么我们必须构建上述模块,使其能够彼此连接,以提供 24x7 良好的购物体验。
Advantages & Disadvantages
以下是一些使用微服务而非使用单体应用程序的优势:
Advantages
-
Small in size - 微服务是 SOA 设计模式的一种实现。建议尽最大程度地保留你的服务。从本质上来说,一个服务不应该执行多于一项业务任务,因此它的体积将明显较小,并且比任何其他单一应用程序都更容易维护。
-
Focused - 如前所述,每个微服务被设计用来只交付一项业务任务。在设计微服务时,架构师应该关注服务的重点,即它的可交付成果。根据定义,一个微服务应本质上是全栈的,并且应致力于只交付一项业务属性。
-
Autonomous - 每个微服务都应是整个应用程序中的一个自治业务单元。因此,应用程序变得更加松散耦合,有助于降低维护成本。
-
Technology heterogeneity - 微服务支持在业务单元中使用的不同技术相互进行通信,这有助于开发人员在正确的位置使用正确的技术。通过实现一个异构系统,可以获得最大的安全性、速度和可扩展系统。
-
Resilience - 恢复力是隔离软件单元的属性。微服务在构建方法中遵循高水平的恢复力,因此当一个单元出现故障时,它不会影响整个业务。恢复力是另一个实施了高度可扩展和松散耦合系统的属性。
-
Ease of deployment - 由于整个应用程序被细分为小单元,每个组件的本质上都应该是全栈的。与同类的其他单一应用程序不同,它们都可以在任何环境中非常轻松地进行部署,并且时间复杂度较低。
以下是有关微服务架构缺点的一些要点。
Microservice Over SOA
下表列出了 SOA 和微服务的某些特性,展示了与 SOA 相比使用微服务的重要性。
Component |
SOA |
Microservice |
Design pattern |
SOA 是计算机软件的设计范例,其中软件组件以服务的形式对外公开,以便使用。 |
微服务是 SOA 的一部分。它是 SOA 的一种专门实现。 |
Dependency |
业务单元相互依赖。 |
所有业务单元彼此独立。 |
Size |
软件规模大于传统软件。 |
Software size is small. |
Technology |
技术栈小于微服务。 |
微服务本质上是异构的,因为使用精确技术来执行特定任务。微服务可以被视为许多技术的集合体。 |
Autonomous and Focus |
SOA 应用程序被构建用来执行多个业务任务。 |
微服务应用程序旨在执行一项业务任务。 |
Nature |
Monolithic in nature. |
Full stack in nature. |
Deployment |
Deployment is time-consuming. |
部署非常容易,因此耗时更少。 |
Cost-effectiveness |
More cost-effective. |
Less cost-effective. |
Scalability |
Less compared to Microservices. |
Fully scaled. |
Example |
我们考虑一个在线出租车预订应用程序。如果我们想要使用 SOA 构建该应用程序,那么它的软件单元将是:GetPayments And DriverInformation And MappingDataAPIAuthenticateUsersAnd DriversAPI。 |
如果使用微服务架构构建同一个应用程序,那么它的 API 将是:SubmitPaymentsServiceGetDriverInfoServiceGetMappingDataServiceAuthenticateUserServiceAuthenticateDriverService。 |
Microservice Architecture - Scaling
伸缩是将软件分解为不同单元的过程。伸缩还从可伸缩性的角度进行定义。可伸缩性是实现应用程序更多高级功能的潜力。它有助于提高应用程序的安全性、持久性和可维护性。我们在行业中采用了三种类型的伸缩程序。以下是不同的伸缩方法以及相应的真实示例。
X-Axis Scaling
X 轴伸缩也称为水平伸缩。在此过程中,整个应用程序被细分为不同的水平部分。通常,任何 Web 服务器应用程序都可以进行这种类型的伸缩。考虑一个遵循水平伸缩的普通 MVC 架构,如下图所示。
例如,我们可以考虑任何 JSP servlet 应用程序。在此应用程序中,控制器控制每个请求,并且它会在必要时与模型通信以生成视图。通常,单体应用程序遵循这种伸缩方法。X 轴伸缩本质上非常基本,并且非常省时。在此方法中,将根据单元负责的不同任务对一款软件进行伸缩。例如,控制器负责控制传入和传出的请求,视图负责向浏览器中的用户表示业务功能,而模型负责存储我们的数据并充当数据库。
Y-Axis Scaling
Y 轴伸缩也称为垂直伸缩,包括任何资源级伸缩。任何 DBaaS 或 Hadoop 系统都可以被认为是 Y 轴伸缩。在此类型的伸缩中,用户请求被重定向并受到限制,方法是实现一些逻辑。
让我们以 Facebook 为例。Facebook 每秒需要处理 179 万用户;因此,控制流量是 Facebook 网络工程师的巨大责任。为了克服任何危险,他们遵循 Y 轴伸缩,其中包括同时运行具有相同应用程序的多个服务器。现在,为了控制这种巨大的流量,Facebook 将所有流量从一个区域重定向到特定服务器,如下图所示。基于区域的这种流量传输在架构语言中称为负载平衡。
将资源分解为小型独立业务单元的这种方法称为 Y 轴伸缩。
Microservice Architecture - Blueprint
微服务在内部实现 SOA。从更广泛的意义上讲,我们可以将其视为一个 SOA 应用程序的子集。
Rule & Workflow
以下是在开发微服务时需要遵循的原则。
-
High Cohesion − 所有业务模型都应尽可能细分到最小的业务部分。每项服务都应专注于只执行一项业务任务。
-
Independent − 所有服务都应本质上是全栈且相互独立的。
-
Business Domain Centric − 软件将根据业务单元模块化,而不是基于层。
-
Automation − 测试部署将自动化。尽量减少人工交互。
-
Observable − 每个服务本质上都是全栈,它们应该可以独立部署和观察,就像企业应用程序一样。
Different Elements
到目前为止,我们已经了解了什么是微服务以及它在现代 MVC 架构之上有哪些基本需求。在本章中,我们将学习此架构的不同元素,这些元素对于服务同等重要。
Categories of Services
按微服务命名,我们假设它将是可以通过 HTTP 协议使用的服务,然而我们需要了解可以使用此架构构建哪种服务。以下是可以使用微服务架构实现的服务列表。
Platform as a Service [PaaS] - 在这种面向服务架构中,平台被赋予一种可以根据业务需求进行定制的工具。PaaS 在移动应用程序开发中发挥着重要作用。PaaS 最好的例子是 Google App Engine,其中 Google 提供了不同的有用平台来构建你的应用程序。PaaS 最初开发是为了向开发人员提供内置架构或基础设施。它在大大减少的时间内降低了更高级别的编程复杂性。以下是 Google 提供的 PaaS 的快照。
Software as a Service [SaaS] - 软件即服务是一种软件许可业务,其中软件集中托管并按订阅方式授权。SaaS 主要可以通过浏览器访问,并且是许多业务垂直领域中非常常见的架构模式,例如人力资源管理 (HRM)、企业资源规划 (ERP)、客户关系管理 (CRM) 等。以下屏幕快照显示了 Oracle 提供的不同 SaaS 的示例。
Infrastructure as a Service [IaaS] - 基础设施在 IT 行业中扮演着重要的角色。使用云计算,一些组织提供虚拟基础设施作为服务。IaaS 对于在软件开发中带来敏捷性、成本效益、安全性、性能和生产力非常有帮助。Amazon EC2 和 Microsoft Azure 是 IaaS 最重要的例子。下图描述了 AWS 的一个例子,其中数据中心被提供为 IaaS。
Data as a Service [DaaS] - 信息技术处理数据,一些顶级行业领导者认为数据将成为社会的新的支撑。DaaS 是这样的一种服务,其中数据与商业集团共享用于研究和分析。DaaS 在数据访问层带来了简单性、敏捷性和安全性。以下是 Oracle Data Cloud 的一个例子,可以根据你自己的业务需求访问或获得许可。
Back End as a Service [BaaS] - BaaS 也称为 MBaaS,表示移动后端即服务。在这种类型的服务中,应用程序的后端将提供给业务部门以供其自己的业务投资。所有推送通知、社交网络服务都属于这种类型的服务。Facebook 和 Twitter 是著名的 BaaS 服务提供商的例子。
Security
在处理大量客户数据时,安全性发挥着重要作用。安全问题与市场上所有类型的服务相关。无论你使用哪种云 - 私有、公有、混合等,都应在各个层面维护安全性。整个安全问题可以大致细分为以下部分:
-
Security issue faced by service providers - 这种类型的安全问题是由 Google、Amazon 等服务提供商面临的。为了确保安全保护,有必要对客户端进行背景调查,特别是那些直接访问云核心的客户端。
-
Security issue faced by consumers - 云具有成本效益,因此在各行各业中得到广泛应用。一些组织将用户详细信息存储在第三方数据中心,并在需要时提取数据。因此,维护安全级别非常重要,这样一位客户的任何私人数据都不应该对任何其他用户可见。
为了防止上述安全问题,以下是组织使用的一些防御机制。
-
Deterrent Control - 了解你的潜在威胁以减少网络攻击。
-
Preventive Control - 维护高级别的身份验证策略以访问你的云。
-
Detective Control - 监控你的用户并检测任何潜在风险。
-
Corrective Control - 与不同的团队紧密合作,并解决在侦探控制阶段出现的各种问题。
Composition Patterns
软件组合是指构建软件产品的方法。它基本上涉及高级软件架构图,其中软件的不同模块将针对特定业务目标进行通信。在本章中,我们将了解组织中广泛使用的不同软件组合模式。在微服务中,我们将每个功能拆分为一个进程。这些服务中的每一个都将具有独立性和全栈特性。
功能分解在构建微服务中发挥着重要作用。它为您的应用程序提供了敏捷性、灵活性和可伸缩性。
Aggregator Pattern
聚合器模式是最简单的 Web 模式,可以在开发微服务时实现。在此组合模式中,一个简单的 Web 模块将充当负载平衡器,这意味着它将根据要求调用不同的服务。以下是描绘具有聚合器设计的简单微服务 Web 应用程序的图表。如下面的图像所示,“聚合器”负责逐个调用不同的服务。如果我们需要对服务 A、B 和 C 的结果应用任何业务逻辑,那么我们可以在聚合器本身中实现业务逻辑。
聚合器可以再次对外界公开为另一项服务,其他人可以在需要时使用它。在开发聚合器模式 Web 服务时,我们需要记住,我们的每个服务 A、B 和 C 都应该有自己的缓存层,并且它本质上应该是全栈的。
Proxy Pattern
代理微服务模式是聚合器模型的一个变体。在这个模型中,我们将使用代理模块来代替聚合模块。代理服务可以单独调用不同的服务。
在代理模式中,我们可以通过提供一个转储代理层来构建一级的额外安全。该层的作用类似于接口。
Chained Pattern
顾名思义,此类型的组合模式将遵循链式结构。在这里,我们不会在客户端和服务层之间使用任何内容。相反,我们将允许客户端直接与服务进行通信,并且所有服务将以这样的方式链接在一起,即一个服务的输出将成为下一个服务的输入。下图显示了一个典型的链式模式微服务。
这种架构的一个主要缺点是,客户端将在整个过程完成前被阻止。因此,强烈建议将链条的长度尽可能短。
Microservice Architecture - Hands-On SOA
在本章中,我们将开发基于 CRUD 的具有 SOA 架构的应用程序。稍后在后续章节中,我们将把该服务分解成微服务,并且我们将学习 SOA 和微服务架构之间的基本区别。
System Configuration and Setup
在本节中,我们将构建一个示例 CRUD 应用程序,无论何时调用我们的服务都会返回 JSON 对象作为响应。我们将使用 Jersey 框架来开发它。以下是设置本地系统环境的步骤。
Developing a CRUD Application
Step 1 − 我们将使用 NetBeans 作为开发 IDE。请下载并安装 NetBeans 官方网站 https://netbeans.org/downloads/ 上可用的最新版本。
Step 2 − 打开您的 NetBeans IDE。转到“文件 → 新建项目”。将弹出以下屏幕截图。选择“Maven”作为类别,选择“Project from ArchType”作为项目,然后点击下一步。
这将下载创建您的第一个 Maven 项目和 RESTful Web Service 所需的所有 jar 文件。
Step 3 − 点击上一步中的下一步按钮,将出现以下屏幕截图。在这里,您必须指定 Maven Archetype。
在搜索框中,搜索“Jersey-archType-Webapp(2.16)”并勾选“显示旧版本”复选框。
Step 4 − 选择它之后,您将被重定向到以下屏幕。从列表中选择首选的 jar,然后点击下一步继续。
Step 5 − 在此步骤中,您需要提供项目的名称及其 Group Id 以及包详细信息。在提供所有这些信息后,点击完成以继续。
Step 6 − 您的工作区设置已完成。项目目录将如下所示。
查看您的“Dependencies”文件夹,您会发现 Maven 已为该项目自动下载了所有必需的 jar 文件。
Step 7 − 您的工作区已完成设置,您可以开始编写代码。继续创建四个类和包,如下面的屏幕截图所示。您会发现 Maven 已经创建了 MyResource.java,因为 Maven 足够聪明,可以检测到您将要构建自己的 Web 服务。
Step 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;
}
}
Step 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
}
}
Step 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);
}
}
Step 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);
}
}
Step 12 − 清理构建项目并运行它。如果一切顺利,那么您应该在访问 http://localhost:8080/UserProfile/webapi/Profile” URL 时在浏览器中获得以下输出。
您可以看到使用 XML 表示填充了不同的条目。
可以通过应用适当的方法 URL 使用 Postman 测试不同的方法。
@GET method − 以下屏幕截图演示了我们如何获得 get 请求所需的返回所有用户详细信息的结果。
@POST − 以下请求可用于测试我们的发布方法。请注意 proId 已自动生成。
@PUT − 此方法将更新条目。下图演示了 Jersey 如何从请求 URL 中获取 proId 并更新相同用户配置文件回复。
您可以用相同方式检查您的 Web 服务中可用的其他方法。
在上一部分中,我们开发了一项服务,将公开 CRUD 功能。现在,无论何时尝试在我们的应用程序中实现此服务,都需要创建此应用程序的客户端并将其附加到我们的应用程序中。在本章中,我们将学习如何使用微服务理念构建此功能。以下是使用上述步骤构建的应用程序的图表表示。
actor 应作为我们服务的入口点。在这种情况中,“ProfileResource.java”担当 actor 的作用。此类将调用不同的方法来执行不同的操作,例如添加、更新和删除。
Decomposition of CRUD Application
根据微服务的核心原则,我们对每个模块只进行一项业务任务,因此一个 actor 不应负责所有四个 CRUD 功能。考虑以下示例,我们在其中引入了一些新的角色,以便您在概念上清楚了解微服务是 SOA 的架构表示。
“主用户”是与“应用程序控制器”通信以满足其需求的用户。“应用程序控制器”是根据最终用户请求只调用不同的“资源管理器”的用户。“资源管理器”执行需要完成的工作。让我们快速了解一下应用程序的不同单元的不同角色。
-
End User/Main Users − 向应用程序控制器请求一些资源。
-
Application − 接收请求并将其转发到特定的资源管理器。
-
Resource Manager − 执行实际的更新、删除和添加用户的工作。
看看一个类的全部责任是如何分布在其他不同类中的。
Microservice Architecture - Hands-On MSA
在本章中,我们将构建一个微服务应用程序,它将消耗不同的可用服务。我们都知道,微服务并不是构建应用程序的经济有效的方法,因为我们构建的每一项服务本质上都是全栈的。在本地环境中构建微服务需要高端系统配置,因为你需要四台服务器实例才能持续运行,以便在某一时间点能消耗它。为了构建我们有史以来的第一个微服务,我们将使用一些可用的 SOA 端点,并在我们的应用程序中消耗它们。
System Configuration and Setup
在进入构建阶段之前,请做好系统准备。你需要一些公共 Web 服务。你可以轻松地进行谷歌搜索。如果你想消耗 SOAP Web 服务,那么你将得到一个 WSDL 文件,然后你需要从中消耗特定的 Web 服务。对于 REST 服务,你只需要一个链接来消耗它。在这个示例中,你将把三个不同的 Web 服务“SOAP”、“REST”和“自定义”嵌入到一个应用程序中。
Application Architecture
你将使用微服务实现计划创建一个 Java 应用程序。你将创建一个自定义服务,此服务的输出将作为其他服务的输入。
下面是开发微服务应用程序的步骤。
Step 1: Client creation for SOAP service − 有许多免费 Web API 可用于学习 Web 服务。为本教程的目的,使用“ http://www.webservicex.net/.” 的 GeoIP 服务。他们的网站上以“ webservicex.net. 提供了 WSDL 文件。要从该 WSDL 文件中生成客户端,你需要做的就是在你的终端中运行以下命令。
wsimport http://www.webservicex.net/geoipservice.asmx?WSDL
此命令将在一个名为“SEI”的文件夹(以服务端点接口命名)下生成所有必需的客户端文件。
Step 2: Create your custom web service − 按照本教程前面阶段中提到的相同过程,构建基于 Maven 的 REST api,名为“CustomRest”。完成后,你会找到一个名为“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 服务器,它在被调用后返回一个字符串对象。这是一项输入服务,它提供可被其他应用程序消耗以生成记录的输入。
Step 3: Configure another Rest API − 在此步骤中,消耗 services.groupkt.com. 可用的另一项 Web 服务。调用时,这将返回一个 JSON 对象。
Step 4: Create JAVA application − 通过选择“新项目”→“JAVA 项目”创建一个正常的 Java 应用程序,然后按如下截图所示单击“完成”。
Step 5: Add the SOAP client − 在步骤 1 中,你创建了 SOAP Web 服务的客户端文件。继续将这些客户端文件添加到你当前的项目。成功添加客户端文件后,你的应用程序目录将如下所示。
Step 6: Create your main app − 创建一个主类,你将在其中消耗所有这三个 Web 服务。右键单击源项目,并创建一个名为“MicroServiceInAction.java”的新类。接下来,从这里调用不同的 Web 服务。
Step 7: Call your custom 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();
}
Step 8: Consume SOAP Services − 你生成了客户端文件,但你不知道该在整个软件包中调用哪个方法?为此,你需要再次参考你用来生成客户端文件的 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());
Step 9: Consume REST web service − 到目前为止已经消耗了其中两项服务。在此步骤中,将在自定义 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();
}
Step 10: Consume all services − 如果你正在运行“CustomRest”Web 服务且已连接到互联网,如果一切都已成功完成,那么以下内容应为你合并的主类。
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();
}
}
}
一旦运行此文件,你将看到控制台中的以下输出。你已成功开发了你的第一个微服务应用程序。