微服务架构 -动手实践 SOA

在本章中,我们将使用 SOA 架构开发基于 CRUD 的应用程序。在后续章节中,我们将把这项服务分解为微服务,并了解 SOA 和微服务架构之间的基本区别。

系统配置和设置

在本节中,我们将构建一个示例 CRUD 应用程序,每当我们调用我们的服务时,它将返回 JSON 对象作为响应。我们将使用 Jersey 框架来开发相同的应用程序。以下是设置本地系统环境的步骤。

开发 CRUD 应用程序

步骤 1 − 我们将使用 NetBeans 作为开发 IDE。请在 NetBeans 官方网站 https://netbeans.org/downloads/ 下载并安装最新版本。

步骤 2 − 打开您的 NetBeans IDE。转到"文件 -> 新建项目"。弹出以下屏幕截图。选择"Maven"作为类别,选择"ArchType 中的项目"作为项目,然后单击下一步。

弹出屏幕截图

这将下载创建您的第一个 Maven 项目和 RESTful Web 服务所需的所有 jar 文件。

步骤 3 − 在上一步中点击下一步按钮后,将出现以下屏幕截图。在这里,您必须指定 Maven Archetype。

Maven Archetype

在搜索框中,搜索"Jersey-archType-Webapp(2.16)"并选中"显示旧版本"复选框。

步骤 4 − 选择相同内容后,您将被重定向到以下屏幕。从列表中选择所需的 jar,然后单击"下一步"继续。

重定向屏幕

步骤 5 − 在此步骤中,您需要提供项目的名称及其组 ID 以及包详细信息。提供所有这些信息后,点击"完成"继续。

Group Id

步骤 6 − 您已完成工作区设置。项目目录将如下所示。

工作区设置

查看"依赖项"文件夹,您会发现 Maven 已自动下载此项目所需的所有 jar 文件。

依赖项

步骤 7 − 您的工作区已设置完毕,您可以开始编码。继续创建四个类和包,如以下屏幕截图所示。您会发现 MyResource.java 已由 Maven 创建,因为 Maven 足够智能,可以检测到您将要构建自己的 Web 服务。

Source Packages

步骤 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();
   
   // 创建一些预定义配置文件并将其填充到地图中
   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 表示填充了不同的条目。

User Profiles

可以通过应用适当的方法 URL 使用 Postman 测试不同的方法。

@GET 方法 − 以下屏幕截图演示了我们如何获得 get 请求的所需结果,该请求返回所有用户详细信息。

Screenshot Demonstrates

@POST −以下请求可用于测试我们的 Post 方法。请注意 proId 是如何自动生成的。

Post 方法

@PUT − 此方法将更新条目。以下屏幕截图演示了 Jersey 如何从请求 URL 获取 proId 并更新相同的用户个人资料回复。

相同的用户个人资料回复

以同样的方式,您可以检查 Web 服务中可用的其他方法。

在上一节中,我们开发了一个将公开 CRUD 功能的服务。现在,每当我们尝试在我们的应用程序中实现此服务时,我们都需要创建此应用程序的客户端并将其附加到我们的应用程序中。在本章中,我们将学习如何使用微服务的概念构建此功能。以下是使用上述步骤构建的应用程序的示意图。

Actor

参与者应该是我们服务的入口点。在本例中,"ProfileResource.java"履行参与者的职责。此类将调用不同的方法来执行不同的操作,例如添加、更新和删除。

CRUD 应用程序的分解

根据微服务的主要原则,我们每个模块只需要一个业务任务,因此一个参与者不应该负责所有四个 CRUD 功能。考虑以下示例,我们引入了一些新角色,以便您从概念上清楚地了解微服务是 SOA 的架构表示。

Architectural Representation

"主要用户"是与"应用程序控制器"通信以满足自己需求的用户。"应用程序控制器"只是根据最终用户的请求调用不同的"资源管理器"。"资源管理器"完成需要完成的工作。让我们快速看一下应用程序不同单元的不同角色。

  • 最终用户/主要用户 − 向应用程序控制器请求一些资源。

  • 应用程序 −接收请求并将其转发给特定的资源管理器。

  • 资源管理器 − 执行更新、删除和添加用户的实际工作。

查看一个类的总职责如何在其他不同类之间分配。