all-things-cqrs 正在参加 2021 年度 OSC 中国开源项目评选,请投票支持!
all-things-cqrs 在 2021 年度 OSC 中国开源项目评选 中已获得 {{ projectVoteCount }} 票,请投票支持!
2021 年度 OSC 中国开源项目评选 正在火热进行中,快来投票支持你喜欢的开源项目!
2021 年度 OSC 中国开源项目评选 >>> 中场回顾
all-things-cqrs 获得 2021 年度 OSC 中国开源项目评选「最佳人气项目」 !
授权协议 Readme
开发语言 Java
操作系统 跨平台
软件类型 开源软件
所属分类 云计算云原生
开源组织
地区 不详
投 递 者 首席测试
适用人群 未知
收录时间 2021-12-09

软件简介

All Things CQRS

A bunch of ways of doing CQRS with various Spring tools.

Getting Started

These instructions will get you and overview of how to synchronize two different datasources. We will do so by separating command and queries in a simple CQRS app. Each module represents a different way of introducing this pattern. Also, each module is a standalone Spring Boot application.

Prerequisites

What things you need to run the software:

Overview

Sample applications are based on a simple domain that serves credit cards. There are two usecases:

  • Money can be withdrawn from a card (Withdraw command)
  • List of withdrawals from a card can be read (query)

The important is that:

After a successful Withdraw command, a withdrawal should be seen in a result from list of withdrawals query.

Hence there is a need for some synchronization that makes state for commands and queries consistent.

Let's agree on a color code for commands, queries and synchronization. It will make our drawings consistent.

color code

Commands and queries handled in one class (no CQRS)

Code can be found under in-one-class module.

Running the app:

mvn spring-boot:run

A sample Withdraw command:

curl localhost:8080/withdrawals -X POST --header 'Content-Type: application/json' -d '{"card":"3a3e99f0-5ad9-47fa-961d-d75fab32ef0e", "amount": 10.00}' --verbose

Verifed by a query:

curl http://localhost:8080/withdrawals?cardId=3a3e99f0-5ad9-47fa-961d-d75fab32ef0e --verbose

Expected result:

[{"amount":10.00}]

Architecture overview:

in-one-class

Automatic E2E test for REST API can be found here:

    @Test
    public void shouldSynchronizeQuerySideAfterSendingACommand() {
        // given
        UUID cardUUid = thereIsCreditCardWithLimit(new BigDecimal(100)); //HTTP POST
        // when
        clientWantsToWithdraw(TEN, cardUUid); //HTTP GET
        // then
        thereIsOneWithdrawalOf(TEN, cardUUid);
    }

CQRS with application service as explicit synchronization

Code can be found under explicit-with-dto module. Same version, but with JPA entities as results of a query can be found here.

Running the app:

mvn spring-boot:run

A sample Withdraw command:

curl localhost:8080/withdrawals -X POST --header 'Content-Type: application/json' -d '{"card":"3a3e99f0-5ad9-47fa-961d-d75fab32ef0e", "amount": 10.00}' --verbose

Verifed by a query:

curl http://localhost:8080/withdrawals?cardId=3a3e99f0-5ad9-47fa-961d-d75fab32ef0e --verbose

Expected result:

[{"amount":10.00}]

Architecture overview:

application-process

Automatic E2E test for REST API can be found here:

    @Test
    public void shouldSynchronizeQuerySideAfterSendingACommand() {
        // given
        UUID cardUUid = thereIsCreditCardWithLimit(new BigDecimal(100)); //HTTP POST
        // when
        clientWantsToWithdraw(TEN, cardUUid); //HTTP GET
        // then
        thereIsOneWithdrawalOf(TEN, cardUUid);
    }

CQRS with spring application events as implicit synchronization

Code can be found under with-application-events module.

There is also a version with immutable domain module which just returns events. It Can be found here.

Running the app:

mvn spring-boot:run

A sample Withdraw command:

curl localhost:8080/withdrawals -X POST --header 'Content-Type: application/json' -d '{"card":"3a3e99f0-5ad9-47fa-961d-d75fab32ef0e", "amount": 10.00}' --verbose

Verifed by a query:

curl http://localhost:8080/withdrawals?cardId=3a3e99f0-5ad9-47fa-961d-d75fab32ef0e --verbose

Expected result:

[{"amount":10.00}]

Architecture overview:

appevents

Automatic E2E test for REST API can be found here:

    @Test
    public void shouldSynchronizeQuerySideAfterSendingACommand() {
        // given
        UUID cardUUid = thereIsCreditCardWithLimit(new BigDecimal(100)); //HTTP POST
        // when
        clientWantsToWithdraw(TEN, cardUUid); //HTTP GET
        // then
        thereIsOneWithdrawalOf(TEN, cardUUid);
    }

CQRS with trigger as implicit synchronization

Code can be found under trigger module.

Running the app:

mvn spring-boot:run

A sample Withdraw command:

curl localhost:8080/withdrawals -X POST --header 'Content-Type: application/json' -d '{"card":"3a3e99f0-5ad9-47fa-961d-d75fab32ef0e", "amount": 10.00}' --verbose

Verifed by a query:

curl http://localhost:8080/withdrawals?cardId=3a3e99f0-5ad9-47fa-961d-d75fab32ef0e --verbose

Expected result:

[{"amount":10.00}]

Architecture overview:

trigger

Automatic E2E test for REST API can be found here:

    @Test
    public void shouldSynchronizeQuerySideAfterSendingACommand() {
        // given
        UUID cardUUid = thereIsCreditCardWithLimit(new BigDecimal(100)); //HTTP POST
        // when
        clientWantsToWithdraw(TEN, cardUUid); //HTTP GET
        // then
        thereIsOneWithdrawalOf(TEN, cardUUid);
    }

CQRS with transaction log tailing as synchronization

Synchronization done by listening to database's transaction log, which is a log of transactions accepted by a database management system.

Code can be found under with-log-tailing module.

Additional components:

  • MySQL to keep withdrawals and credit cards.
  • Apache Kafka for pub/sub for messages read from database transaction log (in this case it is MySQL).
  • Kafka Connect with Debezium to read MySQL’s transaction log and stream messages to Kafka’s topic.
  • Spring Cloud Stream to read messages from Kafka’s topic.

Running the app, remember to be in root of the project:

  • In docker-compose.yaml, under service kafka - CHANGE IP to match your host machine. Keep port pointing to 9092:
ADVERTISED_LISTENERS=PLAINTEXT://YOUR_HOST_IP:9092
  • Run the whole infrastructure:
docker-compose up
  • Tell Kafka Connect to tail transaction log of MySQL DB and send messages to Kafka:
curl -i -X POST -H "Accept:application/json" -H  "Content-Type:application/json" http://localhost:8083/connectors/ -d @source.json --verbose

A sample Withdraw command:

curl localhost:8080/withdrawals -X POST --header 'Content-Type: application/json' -d '{"card":"3a3e99f0-5ad9-47fa-961d-d75fab32ef0e", "amount": 10.00}' --verbose

Verifed by a query:

curl http://localhost:8080/withdrawals?cardId=3a3e99f0-5ad9-47fa-961d-d75fab32ef0e --verbose

Expected result can be seen below. Remember that it takes time to read transaction log and create a withdrawal. Hence a withdrawal might be not immedietly seen:

[{"amount":10.00}]

Architecture overview:

logtailing

Since it is problematic (or immposible) to test transaction log tailing, there is no E2E test that verifies commands and queries. But we can test if a message arrival in Kafka's topic results in a proper withdrawal created. The code is here:

    @Test
    public void shouldSynchronizeQuerySideAfterLogTailing() {
        // given
        String cardUUid = thereIsCreditCardWithLimit(new BigDecimal(100));
        // when
        creditCardUpdateReadFromDbTransactionLog(TEN, cardUUid);
        // then
        thereIsOneWithdrawalOf(TEN, cardUUid);
    }

CQRS with Domain Events as synchronization

Synchronization done by sending a domain event after succesfully handling a command.

Code can be found under events module. It has 2 further modules, architecture is fully distributed. There is a source (deals with commands) and sink (deals with queries).

Additional components:

  • H2 DB to keep credit cards.
  • MongoDB to keep withdrawals.
  • Spring Data Reactive MongoDb to reactively talk to Mongo
  • Project Reactor to serve non-blocking web-service
  • Apache Kafka for pub/sub for domain events
  • Spring Cloud Stream to read/write messages from/to Kafka’s topic.

Running the app, remember to be in root of the project:

  • Run the whole infrastructure:
docker-compose up

A sample Withdraw command:

curl localhost:8080/withdrawals -X POST --header 'Content-Type: application/json' -d '{"card":"3a3e99f0-5ad9-47fa-961d-d75fab32ef0e", "amount": 10.00}' --verbose

Verifed by a query (notifce a different port: 8888!):

curl http://localhost:8888/withdrawals?cardId=3a3e99f0-5ad9-47fa-961d-d75fab32ef0e --verbose

Expected result can be seen below. Remember that it takes time to publish and read domain events from Kafka. Hence a withdrawal might be not immedietly seen:

[{"amount":10.00}]

Architecture overview:

events

Since it is not recommended to test 2 microservices in one test, there is no E2E test that verifies commands and queries. But we can test if a message arrival in Kafka's topic results in a proper withdrawal created. The code is here:

    @Test
    public void shouldSeeWithdrawalAfterGettingAnEvent() {
        //when
        anEventAboutWithdrawalCame(TEN, cardID);

        //then
        thereIsOneWithdrawalOf(TEN, cardID);
    }

Also it is possible to test if a successful withdrawal is followed eventually by a proper domain event publication. The code is here.

    @Test
    public void shouldEventuallySendAnEventAboutCardWithdrawal() throws IOException {
        // given
        UUID cardUUid = thereIsCreditCardWithLimit(new BigDecimal(100));
        // when
        clientWantsToWithdraw(TEN, cardUUid);
        // then
        await().atMost(FIVE_SECONDS).until(() -> eventAboutWithdrawalWasSent(TEN, cardUUid));
    }

CQRS with Axon Framework

Take a look here

展开阅读全文

代码

评论

点击引领话题📣
暂无内容
发表了博客
{{o.pubDate | formatDate}}

{{formatAllHtml(o.title)}}

{{parseInt(o.replyCount) | bigNumberTransform}}
{{parseInt(o.viewCount) | bigNumberTransform}}
没有更多内容
暂无内容
发表了问答
{{o.pubDate | formatDate}}

{{formatAllHtml(o.title)}}

{{parseInt(o.replyCount) | bigNumberTransform}}
{{parseInt(o.viewCount) | bigNumberTransform}}
没有更多内容
暂无内容
Spring Data MongoDB SpEL 表达式注入漏洞
表达式注入
Spring Data MongoDB基于 Spring 编程模型为 MongoDB 提供抽象接口和通用性模型。 应用程序对包含查询参数占位符的SpEL表达式使用 @Query 或 @Aggregation-annotated 查询方法进行值绑定时,如果未过滤输入内容,则可能导致 SpEL 表达式注入漏洞。 攻击者可通过该漏洞进行任意命令执行。
CVE-2022-22980 MPS-2022-1110
2022-08-08 18:09
Hibernate Validator 跨站脚本漏洞
XSS
Hibernate Validator是一款参数校验框架。 Hibernate Validator中存在跨站脚本漏洞。该漏洞源于WEB应用缺少对客户端数据的正确验证。攻击者可利用该漏洞执行客户端代码。
CVE-2019-10219 MPS-2019-14389
2022-08-08 18:09
dom4j XML注入漏洞
XPath盲注
dom4j是一款支持DOM、SAX、JAXP和Java平台的用于处理XML文件的开源框架。 dom4j 2.1.1之前版本中的Class:Element存在安全漏洞,该漏洞源于程序没有验证输入。攻击者可通过指定XML文档中的属性或元素利用该漏洞执行篡改操作。
CVE-2018-1000632 MPS-2018-11300
2022-08-08 18:09
FasterXML jackson-databind 代码问题漏洞
反序列化
FasterXML jackson-databind是一个基于JAVA可以将XML和JSON等数据格式与JAVA对象进行转换的库。Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。 FasterXML jackson-databind 2.0.0版本至2.9.10版本中存在代码问题漏洞。该漏洞源于网络系统或产品的代码开发过程中存在设计或实现不当的问题。攻击者可通过发送特制请求利用该漏洞在系统上执行任意代码。
CVE-2019-16942 MPS-2019-12479
2022-08-08 18:09
FasterXML jackson-databind 代码问题漏洞
反序列化
2.9.10.8 之前的 FasterXML jackson-databind 2.x 错误处理了与 org.apache.commons.dbcp2.datasources.SharedPoolDataSource 相关的序列化小工具和类型之间的交互。
CVE-2020-35491 MPS-2020-17697
2022-08-08 18:09
FasterXML jackson-databind代码问题漏洞
反序列化
FasterXML Jackson是美国FasterXML公司的一款适用于Java的数据处理工具。jackson-databind是其中的一个具有数据绑定功能的组件。 FasterXML jackson-databind 2.9.10.5之前的2.x版本中存在安全漏洞。目前没有详细漏洞细节提供。
CVE-2020-14060 MPS-2020-8803
2022-08-08 18:09
FasterXML jackson-databind 代码问题漏洞
反序列化
FasterXML jackson-databind是一个基于JAVA可以将XML和JSON等数据格式与JAVA对象进行转换的库。Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。 FasterXML jackson-databind 2.x before 2.9.10.8 存在代码问题漏洞,该漏洞源于com.newrelic.agent.deps.ch.qos.logback.core.db.JNDIConnectionSource错误地处理serialization gadgets 和 typing的交互。
CVE-2020-36188 MPS-2021-0211
2022-08-08 18:09
Apache Tomcat 信息泄露漏洞
Apache Tomcat是美国阿帕奇(Apache)基金会的一款轻量级Web应用服务器。 Apache Tomcat存在信息泄露漏洞,该漏洞源于可以在响应新的 h2c 连接请求时复制请求头和数量有限的请求体,这意味着用户a和用户B都可以看到用户a的请求结果。
CVE-2021-25122 MPS-2021-2309
2022-08-08 18:09
FasterXML Jackson-databind代码问题漏洞
反序列化
FasterXML Jackson是美国FasterXML公司的一款用于Java的数据处理工具。Jackson-databind是其中的一个具有数据绑定功能的组件。 FasterXML Jackson-databind 2.9.8之前的2.x版本中存在安全漏洞。攻击者可利用该漏洞执行代码。
CVE-2018-19362 MPS-2019-0025
2022-08-08 18:09
FasterXML jackson-databind 信息泄露漏洞
反序列化
FasterXML Jackson是美国FasterXML公司的一款适用于Java的数据处理工具。jackson-databind是其中的一个具有数据绑定功能的组件。 FasterXML jackson-databind 2.9.9.2之前的2.x版本中存在安全漏洞。目前尚无此漏洞的相关信息,请随时关注CNNVD或厂商公告。
CVE-2019-14439 MPS-2019-8770
2022-08-08 18:09
FasterXML jackson-databind代码问题漏洞
反序列化
FasterXML Jackson是美国FasterXML公司的一款适用于Java的数据处理工具。jackson-databind是其中的一个具有数据绑定功能的组件。 FasterXML jackson-databind 2.9.10.5之前的2.x版本中存在安全漏洞。目前没有详细漏洞细节提供。
CVE-2020-14061 MPS-2020-8801
2022-08-08 18:09
FasterXML jackson-databind 代码问题漏洞
反序列化
FasterXML jackson-databind是一个基于JAVA可以将XML和JSON等数据格式与JAVA对象进行转换的库。Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。 FasterXML jackson-databind 2.x before 2.9.10.8 存在代码问题漏洞,该漏洞源于org.apache.tomcat.dbcp.dbcp2.datasources.PerUserPoolDataSource错误地处理serialization gadgets 和 typing的交互。
CVE-2020-36184 MPS-2021-0207
2022-08-08 18:09
Netty Snappy资源穷尽漏洞
拒绝服务
Netty是Netty社区的一款非阻塞I/O客户端-服务器框架,它主要用于开发Java网络应用程序,如协议服务器和客户端等。 netty存在资源管理错误漏洞,该漏洞源于Snappy frame decoder函数不限制块长度,这可能会导致过度内存使用。
CVE-2021-37137 MPS-2021-28117
2022-08-08 18:09
Apache Tomcat 环境问题漏洞
HTTP请求的解释不一致性(HTTP请求私运)
Apache Tomcat是美国阿帕奇(Apache)基金会的一款轻量级Web应用服务器。该程序实现了对Servlet和JavaServer Page(JSP)的支持。 Apache Tomcat存在环境问题漏洞,该漏洞源于Apache Tomcat 在某些情况下没有正确解析 HTTP 传输编码请求标头,导致在与反向代理一起使用时可能会请求走私。
CVE-2021-33037 MPS-2021-9711
2022-08-08 18:09
Apache Tomcat 操作系统命令注入漏洞
命令注入
Apache Tomcat是美国阿帕奇(Apache)基金会的一款轻量级Web应用服务器。该程序实现了对Servlet和JavaServer Page(JSP)的支持。 Apache Tomcat 9.0.0.M1版本至9.0.17版本、8.5.0版本至8.5.39版本和7.0.0版本至7.0.93版本中的CGI Servlet存在操作系统命令注入漏洞。远程攻击者可利用该漏洞执行代码。
CVE-2019-0232 MPS-2019-4006
2022-08-08 18:09
Netty ZlibDecoders资源管理错误漏洞
不加限制或调节的资源分配
Netty是Netty社区的一款非阻塞I/O客户端-服务器框架,它主要用于开发Java网络应用程序,如协议服务器和客户端等。 Netty 4.1.46之前的4.1.x版本中的ZlibDecoders存在资源管理错误漏洞,该漏洞源于程序在解码ZlibEncoded字节流时没有限制内存分配。攻击者可通过发送大量ZlibEncoded字节流到Netty服务器利用该漏洞占用资源,导致拒绝服务。
CVE-2020-11612 MPS-2020-5127
2022-08-08 18:09
Apache Tomcat跨站脚本漏洞
XSS
Apache Tomcat是美国阿帕奇(Apache)软件基金会的一款轻量级Web应用服务器。该程序实现了对Servlet和JavaServer Page(JSP)的支持。 Apache Tomcat中存在跨站脚本漏洞,攻击者可利用该漏洞执行客户端代码。
CVE-2019-0221 MPS-2019-5944
2022-08-08 18:09
MySQL JDBC XXE漏洞
XXE
Oracle MySQL是美国甲骨文(Oracle)公司的一套开源的关系数据库管理系统。 Oracle MySQL 的 MySQL Connectors 产品中存在XXE漏洞,造成漏洞的原因主要是因为getSource方法未对传入的XML格式数据进行检验。导致攻击者可构造恶意的XML数据引入外部实体,造成XXE攻击。攻击者可能利用该漏洞进行任意文件读取。
CVE-2021-2471 MPS-2020-38350
2022-08-08 18:09
FasterXML jackson-databind 代码问题漏洞
反序列化
2.9.10.8 之前的 FasterXML jackson-databind 2.x 错误处理了与 com.newrelic.agent.deps.ch.qos.logback.core.db.DriverManagerConnectionSource 相关的序列化小工具和类型之间的交互。
CVE-2020-36189 MPS-2021-0212
2022-08-08 18:09
H2Console 存在代码注入
代码注入
H2Console是一个用 Java 编写的可嵌入 RDBMS。 H2Console 2.1.210之前版本存在安全漏洞,攻击者可利用该漏洞通过精心构建的命令在系统上执行任意代码。
CVE-2022-23221 MPS-2022-1435
2022-08-08 18:09
没有更多内容
加载失败,请刷新页面
点击加载更多
加载中
下一页
0 评论
0 收藏
分享
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部