Skip to main content

moregeek program

java微服务六边形结构简介_wx630f055ce23fc的博客-多极客编程

本文将在 Java 中实现 Hexagonal Architecture 的基本概念。

六边形 ​架构 ​​:

六边形架构是一种用于设计软件的架构模式。它旨在创建以核心业务逻辑或领域为中心的松散耦合的可互换软件组件。

原则:

在六边形架构中,应用程序包含三个部分:

  1. 用户端或驱动端
  2. 业务逻辑
  3. 服务器端或驱动端

Java微服务六边形结构简介_应用程序

用户端:

这是用户或任何外部应用程序与应用程序交互的部分。换句话说,应用程序的用户界面。 这部分的例子:

  1. 控制台或命令行
  2. HTTP API 层和一组处理请求的控制器
  3. 一个定时任务

在这里,我们有调用业务流程的参与者。所以这是应用程序的驱动方面。

业务逻辑:

这部分构成了应用程序的核心。它为来自用户界面的请求提供服务。根据请求,它执行一些特定的逻辑,请求逻辑所需的资源,最后将预定义的响应发送回用户界面。定义业务逻辑的主要组件是:

  • 实体是域对象。他们不知道他们存储在哪里。
  • 存储库具有与服务器端通信并返回单个实体或实体列表的方法列表。
  • 交互器是实现业务逻辑、验证等的特定于领域的服务类。用户端通过交互器调用业务流程。

服务器端:

这一面由支持业务逻辑的服务组成。它们中的每一个都有特定的用途,并为业务逻辑层提供资源/数据。 这部分的例子:

  1. 数据源,如关系数据库(例如 PostgreSQL)、非关系或基于文档的数据库(例如 MongoDB)、文件系统、JSON API 数据源、GraphQL 数据源等。
  2. 另一个服务或​微服务

所以,在这里,我们有由业务逻辑驱动的参与者。

Java微服务六边形结构简介_应用程序_02

松耦合和互换性:

现在我们已经了解了系统的基本部分,我们深入研究了部分之间的耦合。到目前为止,我们知道:

  • 用户端 -> 业务逻辑通信通过交互器发生
  • 业务逻辑 -> 服务器端通信通过存储库发生

因此,只要用户端和交互者之间的契约是固定的,用户端的任何参与者,无论是命令行还是 HTTP API 控制器,都可以调用相同的业务流程。类似地,业务逻辑可以从任何类型的数据源或服务接收实体,只要数据源实现存储库中列出的相同方法即可。换句话说,这些通信必须有一个固定的合同。

在 Java 中,这些合约是使用接口实现的。因此,我们已经可以得出结论,存储库只不过是接口。虽然,用户端可以轻松地从 Interactor 或 Service 类调用方法,而无需 Interactor 类实现接口。但是 Interactor 类可以有其他用户端不应该知道的方法。

总而言之,用户端通过业务逻辑中定义的接口来驱动业务逻辑。业务逻辑通过同样在业务逻辑中定义的接口驱动服务器端。

在六边形架构中,我们称接口为ports。

但是,来自用户端和服务器端的不同参与者有不同的技术实现和数据格式。因此,这些参与者必须调整他们的数据格式和逻辑以从端口或接口调用方法。这就是为什么它们在六边形架构中也被称为适配器。

因此,六边形架构有时被称为端口和适配器架构。

Java微服务六边形结构简介_数据源_03

Java 中的示例:

为了理解上述原理,我们将以一个将书籍列表写入标准控制台的命令行应用程序为例。为此,应用程序将在外部文件系统中搜索书籍。组件如下图所示。

Java微服务六边形结构简介_业务逻辑_04

让我们实现应用程序的不同方面:

1、业务逻辑或领域:

这是我们的Book 实体:

<b>public</b> <b>class</b> Book {
<b>private</b> <b>int</b> id;
<b>private</b> String name;
<b>private</b> String author;
<b>public</b> Book(<b>int</b> id, String name, String author) {
<b>this</b>.id = id;
<b>this</b>.name = name;
<b>this</b>.author = author;
} <font><i>// getter 和 setter </i></font><font>
}
</font>

接口/端口:这是我们的接口:

图书服务:

<b>public</b>  IBookService { 
List<Book> getBookList();
}

书库:

<b>public</b>  BookRepository { 
List<Book> getAllBooks ();
}

交互器或服务类。我们将其称为BookService:

<b>public</b> BookService implements  IBookService { 
<b>private</b> BookRepository bookRepository; 公共 BookService(BookRepository bookRepository) {
<b>this</b>.bookRepository = bookRepository;
} @Override
<b>public</b> List<Book> getBookList() {
<b>return</b> bookRepository.getAllBooks();
}
}

用户端:

这是我们的 ConsoleAdapter。我们将其称为BookConsoleUI:

<b>public</b> <b>class</b> BookConsoleUI {
<b>private</b> IBookService bookService;
<b>public</b> BookConsoleUI(IBookService bookService) {
<b>this</b>.bookService = bookService;
}
<b>public</b> <b>void</b> showBooks() {
List<Book> books = bookService.getBookList();
printBooksToConsole(books);
} <b>public</b> <b>void</b> printBooksToConsole(List<Book> books) {
<font><i>// 将书籍打印到控制台的逻辑在这里</i></font><font>
}
}
</font>

服务器端:

这是我们的文件适配器。我们将其称为FileDataSource:

<b>public</b> FileDataSource implements  BookRepository {    
@Override
<b>public</b> List<Book> getAllBooks() {
<b>return</b> getBooksFromFile().stream()
.map(<b>this</b>::mapBookStringToBook)
.collect(Collectors.toList());
}
<b>public</b> List<String> getBooksFromFile() {
<font><i>// 从文件中读取图书数据的代码放在这里</i></font><font>
}
<b>private</b> Book mapBookStringToBook(String bookString) {
String[] bookDetails = bookString.split(</font><font>";"</font><font>);
<b>return</b> <b>new</b> Book(Integer.parseInt(bookDetails[0]), bookDetails[1], bookDetails[2]);
}
}
</font>

一切都放在一起:

让我们看看如何将应用程序的每一端连接在一起:

<font><i>// 实例化 FileAdapter </i></font><font>
FileDataSource fileDataSource = <b>new</b> FileDataSource();
</font><font><i>// 将数据源插入 Interactor </i></font><font>
BookService bookService = <b>new</b> BookService(fileDataSource);
</font><font><i>// 将交互器或服务插入 ConsoleUI </i></font><font>
BookConsoleUI userInterface = <b>new</b> BookConsoleUI(bookService);
</font><font><i>// 通过用户界面驱动业务逻辑</i></font><font>
userInterface.showBooks();
</font>

在这里,我们可以看到,如果我们想要交换数据源,我们只需要实例化该数据源并将其插入 BookService,因为 BookService 将 BookRepository 的引用作为其构造函数参数。

我们看到了如何在 Java 中轻松实现六边形架构的基本方面。该示例的代码可在 ​​GitHub 上​​ 获得。

©著作权归作者所有:来自51CTO博客作者小二上酒8的原创作品,请联系作者获取转载授权,否则将追究法律责任

详谈 mysql 8.0 原子 ddl 原理_wx630f055ce23fc的博客-多极客编程

背景MySQL 5.7 的字典信息保存在非事务表中,并且存放在不同的文件中(.FRM,.PAR,.OPT,.TRN,.TRG 等)。所有 DDL 操作都不是 Crash Safe,而且对于组合 DDL(ALTER 多个表)会出现有的成功有的失败的情况,而不是总体失败。这样主从复制就出现了问题,也导致基于复制的高可用系统不再安全。MySQL 8.0 推出新特性 - 原子 DDL,解决了以上的问题。什

详解mysql中的锁机制_是温度呀的博客-多极客编程

锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的 计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一 个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。本章我们着重讨论MySQL锁机制 的特点,常见的锁问题,以及解决My

linux下安装mysql_write less,do more。的博客-多极客编程

下载 进入http://dev.mysql.com/downloads/mysql/,通过下拉框可以下载对应系统环境的MySQL 可以通过选中Archives下载历史版本的MySQL。 或者使用wget下载: wget http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-5.6.22-1.el6.i686.rpm-bundle.tar 安装 检

java:list 与 数组 相互转换_wx630f055ce23fc的博客-多极客编程

一、 List 转化成 数组list.toArray(); 直接将 list 转换成 Object[] 类型的 数组;Object : 对象类,是所有类的父类Object[] ans1 = list.toArray();list.toArray(T[] a); 输出指定类型的数组,输出的数组类型与括号中参数类型一致;必须是包装类(String、Integer、Character等),不能是基本数

#yyds干货盘点# leetcode 热题 hot 100:无重复字符的最长子串_灰太狼_cxh的博客-多极客编程

题目:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1:输入: s = "abcabcbb"输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。示例 2:输入: s = "bbbbb"输出: 1解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。示例 3:输入: s = "pwwkew"输出: 3解释: 因为无重复字符的最长子串是

#yyds干货盘点# 面试必刷top101:滑动窗口的最大值_风的博客-多极客编程

1.简述:描述给定一个长度为 n 的数组 nums 和滑动窗口的大小 size ,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5

详谈 mysql 8.0 原子 ddl 原理_wx630f055ce23fc的博客-多极客编程

背景MySQL 5.7 的字典信息保存在非事务表中,并且存放在不同的文件中(.FRM,.PAR,.OPT,.TRN,.TRG 等)。所有 DDL 操作都不是 Crash Safe,而且对于组合 DDL(ALTER 多个表)会出现有的成功有的失败的情况,而不是总体失败。这样主从复制就出现了问题,也导致基于复制的高可用系统不再安全。MySQL 8.0 推出新特性 - 原子 DDL,解决了以上的问题。什

go客户之登录_zzxiaoma的博客-多极客编程

1、首先在templates文件夹下建立login.html。 <form class="form form-horizontal" action="/login" method="post"> <div class="row cl"> <label class="form-label col-xs-3"><i class="Hui-iconfo

详解mysql中的锁机制_是温度呀的博客-多极客编程

锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的 计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一 个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。本章我们着重讨论MySQL锁机制 的特点,常见的锁问题,以及解决My

java:list 与 数组 相互转换_wx630f055ce23fc的博客-多极客编程

一、 List 转化成 数组list.toArray(); 直接将 list 转换成 Object[] 类型的 数组;Object : 对象类,是所有类的父类Object[] ans1 = list.toArray();list.toArray(T[] a); 输出指定类型的数组,输出的数组类型与括号中参数类型一致;必须是包装类(String、Integer、Character等),不能是基本数

串的定义及朴素的模式匹配算法_wx619474981d7fe的博客-多极客编程

1 串(String)的定义 早先在计算机在被发明时,主要作用是做一些科学和工程的工作,也就是类似于现在的计算器,只不过是比计算器功能更强大,速度更快一些。但是后来随着社会和技术的发展,在计算机上作废树脂处理的工作越来越多,使得我们不得不引入对字符的处理,于是就有了我们今天字符串的概念。 串的定义:串是由零个或多个字符组成的有限序列,又叫字符串。 一般记为$s=”a_1a_2···a_n (n\g

超简单的python教程系列——第11篇:lambda、装饰器和其他_freestu的博客-多极客编程

Python 以看起来像魔术而闻名,这可能部分归因于函数可以采用多种形式:lambda、装饰器、闭包等等。一个良好的函数调用可以做惊人的事情,而无需编写一个类!你可能会说函数就是魔法。重新认识函数我们已经接触过​​数据类型和不变性​​中的函数。如果你还没有读过那篇文章,我建议你现在回去看看。让我们看一个函数的简单示例,以确保我们在同一维度。def cheer(volume=None): if