Microservice Architecture 简明教程
Microservice Architecture - Hands-On SOA
在本章中,我们将开发基于 CRUD 的具有 SOA 架构的应用程序。稍后在后续章节中,我们将把该服务分解成微服务,并且我们将学习 SOA 和微服务架构之间的基本区别。
In this chapter, we will develop a CRUD-based application with SOA architecture. Later on in the subsequent chapters, we will break this service into microservice and we will learn the basic difference between SOA and microservice architecture.
System Configuration and Setup
在本节中,我们将构建一个示例 CRUD 应用程序,无论何时调用我们的服务都会返回 JSON 对象作为响应。我们将使用 Jersey 框架来开发它。以下是设置本地系统环境的步骤。
In this section, we will build a sample CRUD application, which will return a JSON object as a response whenever we call our service. We will use the Jersey framework to develop the same. Following are the steps to set up your local system environment.
Developing a CRUD Application
Step 1 − 我们将使用 NetBeans 作为开发 IDE。请下载并安装 NetBeans 官方网站 https://netbeans.org/downloads/ 上可用的最新版本。
Step 1 − We will use NetBeans as development IDE. Please download and install the latest version available on NetBeans official website https://netbeans.org/downloads/.
Step 2 − 打开您的 NetBeans IDE。转到“文件 → 新建项目”。将弹出以下屏幕截图。选择“Maven”作为类别,选择“Project from ArchType”作为项目,然后点击下一步。
Step 2 − Open your NetBeans IDE. Go to “File → New Project”. The following screenshot pops up. Choose “Maven” as a category and select “Project from ArchType” as a project and hit Next.
这将下载创建您的第一个 Maven 项目和 RESTful Web Service 所需的所有 jar 文件。
This will download all the required jar files to create your first ever Maven project and RESTful Web Service.
Step 3 − 点击上一步中的下一步按钮,将出现以下屏幕截图。在这里,您必须指定 Maven Archetype。
Step 3 − On hitting the Next button in the previous step, the following screenshot appears. Here, you will have to specify the Maven Archetype.
在搜索框中,搜索“Jersey-archType-Webapp(2.16)”并勾选“显示旧版本”复选框。
In the search box, search for “Jersey-archType-Webapp(2.16)” and check the “Show Older” checkbox.
Step 4 − 选择它之后,您将被重定向到以下屏幕。从列表中选择首选的 jar,然后点击下一步继续。
Step 4 − Once you have selected the same, you will be redirected to the following screen. Select the preferred jar from the list and hit Next to continue.
Step 5 − 在此步骤中,您需要提供项目的名称及其 Group Id 以及包详细信息。在提供所有这些信息后,点击完成以继续。
Step 5 − In this step, you need to provide the name of your project and its Group Id as well as the package details. After providing all this information, hit Finish to continue.
Step 6 − 您的工作区设置已完成。项目目录将如下所示。
Step 6 − You are done with your workspace setup. The project directory will look like the following.
查看您的“Dependencies”文件夹,您会发现 Maven 已为该项目自动下载了所有必需的 jar 文件。
Check out your “Dependencies” folder and you will find that Maven has automatically downloaded all the required jar files for this project.
Step 7 − 您的工作区已完成设置,您可以开始编写代码。继续创建四个类和包,如下面的屏幕截图所示。您会发现 Maven 已经创建了 MyResource.java,因为 Maven 足够聪明,可以检测到您将要构建自己的 Web 服务。
Step 7 − Your workspace is set up and you can start with coding. Go ahead and create four classes and packages as mentioned in the following screenshot. You can find MyResource.java is already created by Maven, as Maven is smart enough to detect that you are going to build your own web service.
Step 8 − 完成上述步骤后,我们将构建我们的 POJO 类 UserProfile.java,如下所示。
Step 8 − Once done with the above step, we will construct our POJO class that is UserProfile.java as follows.
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 上进行操作。
Step 9 − Now we will create our Database class. As this is a part of learning material, we will not use any DB as our database. We will use an inbuilt Java memory to work as our temporary memory. As you can see in the following set of code, we will use MAP as our database. All the web service operation that we perform, we will work on this MAP defined in the class.
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 的引用,以便可以在此类中访问我们的临时数据库。
Step 10 − Now let us build our service class. Go ahead and copy paste the following set of code in the “ProfileService.java” class. This is the class where we will declare all our web service methods that is to be exposed for the outer world. We need to create one reference of our DatabaseClass such that our temporary database can be accessed in this class.
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 的资源类,并将调用相应服务。
Step 11 − In this step, we will create our Resource class that will be linked with the URL and the corresponding service will be called.
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 时在浏览器中获得以下输出。
Step 12 − Clean build the project and run it. If everything goes well then you should get the following output in the browser, while accessing http://localhost:8080/UserProfile/webapi/Profile” URL.
您可以看到使用 XML 表示填充了不同的条目。
You can see different entries are populated using XML representation.
可以通过应用适当的方法 URL 使用 Postman 测试不同的方法。
Different method can be tested using Postman by applying proper method URL.
@GET method − 以下屏幕截图演示了我们如何获得 get 请求所需的返回所有用户详细信息的结果。
@GET method − The following screenshot demonstrates how we can get the desired result for get request, which returns all user details.
@POST − 以下请求可用于测试我们的发布方法。请注意 proId 已自动生成。
@POST − The following request can be used to test our Post method. Notice how the proId has been generated automatically.
@PUT − 此方法将更新条目。下图演示了 Jersey 如何从请求 URL 中获取 proId 并更新相同用户配置文件回复。
@PUT − This method will update the entries. The following screenshot demonstrates how Jersey takes the proId from the request URL and updates the same user profile reply.
您可以用相同方式检查您的 Web 服务中可用的其他方法。
In the same way, you can check for other methods available in your web services.
在上一部分中,我们开发了一项服务,将公开 CRUD 功能。现在,无论何时尝试在我们的应用程序中实现此服务,都需要创建此应用程序的客户端并将其附加到我们的应用程序中。在本章中,我们将学习如何使用微服务理念构建此功能。以下是使用上述步骤构建的应用程序的图表表示。
In the previous section, we have developed one service which will expose CRUD functionality. Now whenever we try to implement this service in our application, we need to create a client of this application and attach it to our application. In this chapter, we will learn how to build this functionality using the concept of Microservice. Following is a diagrammatic representation of our application built using the above steps.
actor 应作为我们服务的入口点。在这种情况中,“ProfileResource.java”担当 actor 的作用。此类将调用不同的方法来执行不同的操作,例如添加、更新和删除。
The actor should be the entry point of our service. In this case “ProfileResource.java” performs the responsibility of an actor. This class will call different methods to perform different operations such as add, update and delete.
Decomposition of CRUD Application
根据微服务的核心原则,我们对每个模块只进行一项业务任务,因此一个 actor 不应负责所有四个 CRUD 功能。考虑以下示例,我们在其中引入了一些新的角色,以便您在概念上清楚了解微服务是 SOA 的架构表示。
According to the main principle of microservice, we need to have only one business task for each of the modules, hence one actor should not be responsible for all four CRUD functionalities. Consider the following example where we have introduced some new roles such that it will be conceptually clear to you that Microservice is an architectural representation of SOA.
“主用户”是与“应用程序控制器”通信以满足其需求的用户。“应用程序控制器”是根据最终用户请求只调用不同的“资源管理器”的用户。“资源管理器”执行需要完成的工作。让我们快速了解一下应用程序的不同单元的不同角色。
“Main user” is the user who communicates with the ”Application Controller” to serve one’s needs. “Application Controller” is the one who just calls different “Resource Managers” depending upon the request from the end user. “Resource Manager” does the job that is required to be done. Let’s take a quick look on the different roles of different units of the application.
-
End User/Main Users − Requests for some resources to Application Controller.
-
Application − Receives the request and forwards the same to specific Resource Manager.
-
Resource Manager − Does the actual job of updating, deleting, and adding users.
看看一个类的全部责任是如何分布在其他不同类中的。
See how the total responsibility of one class is distributed among different other classes.