diff --git a/best-practice/css-webflux/reative-spring-css/README.md b/best-practice/css-webflux/reative-spring-css/README.md new file mode 100644 index 0000000..47b053c --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/README.md @@ -0,0 +1,12 @@ +# 基于 响应式的 客户管理系统 + + +## 设计 +- 该项目中的Web服务设计 +> generateCustomerTicket{ +> 创建 CustomerTicket 对象 +> 从远程 account-service 中获取 Account 对象 +> 从远程 order-service 中获取 Order 对象 +> 设置 CustomerTicket 对象属性 +> 保存 CustomerTicket 对象并返回 +> } \ No newline at end of file diff --git a/best-practice/css-webflux/reative-spring-css/account-service/pom.xml b/best-practice/css-webflux/reative-spring-css/account-service/pom.xml new file mode 100644 index 0000000..fea2ccd --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/account-service/pom.xml @@ -0,0 +1,93 @@ + + + + reative-spring-css + org.example + 1.0-SNAPSHOT + + 4.0.0 + account-service + 1.0.0-REALSE + jar + + Account Service + + + 8 + 8 + + + + + + + + + + + + + + + + + + + + + + + org.springframework.boot + spring-boot-starter-data-mongodb-reactive + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.cloud + spring-cloud-stream + + + org.springframework.cloud + spring-cloud-stream-reactive + 2.2.1.RELEASE + + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + + + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/AccountApplication.java b/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/AccountApplication.java new file mode 100644 index 0000000..80d36a3 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/AccountApplication.java @@ -0,0 +1,14 @@ +package com.baiye; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.stream.annotation.EnableBinding; + +@SpringBootApplication +//@EnableBinding(Source.class) +public class AccountApplication { + + public static void main(String[] args) { + SpringApplication.run(AccountApplication.class, args); + } +} diff --git a/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/conroller/AccountController.java b/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/conroller/AccountController.java new file mode 100644 index 0000000..abedaaf --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/conroller/AccountController.java @@ -0,0 +1,52 @@ +package com.baiye.conroller; + +import com.baiye.domain.Account; +import com.baiye.service.AccountService; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Mono; + +/** + * Account 对应的响应式端点暴露 + */ +@RestController +@RequestMapping(value = "accounts") +public class AccountController { + + + private final AccountService accountService; + + public AccountController(AccountService accountService) { + this.accountService = accountService; + } + + @GetMapping(value = "/{accountId}") + public Mono getAccountById(@PathVariable("accountId") String accountId) { +// +// Account account = new Account(); +// account.setId(1L); +// account.setAccountCode("DemoCode"); +// account.setAccountName("DemoName"); + + Mono account = accountService.getAccountById(accountId); + return account; + } + + @PostMapping(value = "/") + public Mono addAccount(@RequestBody Mono account) { + + return accountService.addAccount(account); + } + + @PutMapping(value = "/") + public Mono updateAccount(@RequestBody Mono account) { + + return accountService.updateAccount(account); + } + + @GetMapping(value = "accountname/{accountName}") + public Mono getAccountByAccountName(@PathVariable("accountName") String accountName) { + + Mono account = accountService.getAccountByAccountName(accountName); + return account; + } +} diff --git a/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/domain/Account.java b/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/domain/Account.java new file mode 100644 index 0000000..9dd7939 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/domain/Account.java @@ -0,0 +1,38 @@ +package com.baiye.domain; + +public class Account { + + private String id; + private String accountCode; + private String accountName; + + public Account() { + super(); + } + + public Account(String id, String accountCode, String accountName) { + super(); + this.id = id; + this.accountCode = accountCode; + this.accountName = accountName; + } + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getAccountCode() { + return accountCode; + } + public void setAccountCode(String accountCode) { + this.accountCode = accountCode; + } + public String getAccountName() { + return accountName; + } + public void setAccountName(String accountName) { + this.accountName = accountName; + } +} diff --git a/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/service/AccountService.java b/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/service/AccountService.java new file mode 100644 index 0000000..a1a5dae --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/service/AccountService.java @@ -0,0 +1,50 @@ +package com.baiye.service; + +import com.baiye.domain.Account; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public interface AccountService { + + /** + * 通过 Id 获取 Account + * @param accountId + * @return + */ + Mono getAccountById(String accountId); + + + /** + * Account 增 + * + * @param account + * @return + */ + Mono addAccount(Mono account); + + + /** + * Account 改 + * + * @param account + * @return + */ + Mono updateAccount(Mono account); + + + /** + * Mono 通过 Name 获取 Account + * @param accountName + * @return + */ + Mono getAccountByAccountName(String accountName); + + + /** + * Flux 通过 Name 获取 Account + * + * @param accountName + * @return + */ + Flux getAccountsByAccountName(String accountName); +} diff --git a/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/service/AccountServiceImpl.java b/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/service/AccountServiceImpl.java new file mode 100644 index 0000000..2489c82 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/account-service/src/main/java/com/baiye/service/AccountServiceImpl.java @@ -0,0 +1,34 @@ +package com.baiye.service; + +import com.baiye.domain.Account; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +@Service +public class AccountServiceImpl implements AccountService{ + @Override + public Mono getAccountById(String accountId) { + return null; + } + + @Override + public Mono addAccount(Mono account) { + return null; + } + + @Override + public Mono updateAccount(Mono account) { + return null; + } + + @Override + public Mono getAccountByAccountName(String accountName) { + return null; + } + + @Override + public Flux getAccountsByAccountName(String accountName) { + return null; + } +} diff --git a/best-practice/css-webflux/reative-spring-css/customer-service/pom.xml b/best-practice/css-webflux/reative-spring-css/customer-service/pom.xml new file mode 100644 index 0000000..5328d77 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/customer-service/pom.xml @@ -0,0 +1,122 @@ + + + + reative-spring-css + org.example + 1.0-SNAPSHOT + + 4.0.0 + customer-service + 1.0.0-RELEASE + jar + + + 8 + 8 + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + spring-libs-snapshot + https://repo.spring.io/libs-snapshot + + + + + + + + + + + + + org.springframework.boot + spring-boot-starter-data-mongodb-reactive + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.cloud + spring-cloud-function-context + + + org.springframework.cloud + spring-cloud-stream-reactive + 2.2.1.RELEASE + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + + + org.springframework.cloud + spring-cloud-stream + + + org.springframework.boot + spring-boot-starter-data-redis-reactive + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.springframework.data + spring-data-redis + + + redis.clients + jedis + + + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/CustomerApplication.java b/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/CustomerApplication.java new file mode 100644 index 0000000..4c89b57 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/CustomerApplication.java @@ -0,0 +1,12 @@ +package com.baiye; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CustomerApplication { + + public static void main(String[] args) { + SpringApplication.run(CustomerApplication.class, args); + } +} diff --git a/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/domain/CustomerTicket.java b/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/domain/CustomerTicket.java new file mode 100644 index 0000000..518588d --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/domain/CustomerTicket.java @@ -0,0 +1,84 @@ +package com.baiye.domain; + +import org.springframework.util.Assert; + +public class CustomerTicket { + + private String id; + private String accountId; + private String orderNumber; + private String description; + private Date createTime; + + + public CustomerTicket() { + super(); + } + + public CustomerTicket(String accountId, String orderNumber) { + super(); + + Assert.notNull(accountId, "Account Id must not be null"); + Assert.notNull(orderNumber, "Order Number must not be null"); + + this.accountId = accountId; + this.orderNumber = orderNumber; + } + + public CustomerTicket(String accountId, String orderNumber, String description, Date createTime) { + + this(accountId, orderNumber); + + this.description = description; + this.createTime = createTime; + } + + public CustomerTicket(String id, String accountId, String orderNumber, String description, Date createTime) { + + this(accountId, orderNumber); + + this.id = id; + this.description = description; + this.createTime = createTime; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAccountId() { + return accountId; + } + + public void setAccountId(String accountId) { + this.accountId = accountId; + } + + public String getOrderNumber() { + return orderNumber; + } + + public void setOrderNumber(String orderNumber) { + this.orderNumber = orderNumber; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} diff --git a/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/service/CustomerTicketService.java b/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/service/CustomerTicketService.java new file mode 100644 index 0000000..679bf71 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/service/CustomerTicketService.java @@ -0,0 +1,10 @@ +package com.baiye.service; + +import com.baiye.domain.CustomerTicket; +import reactor.core.publisher.Mono; + +public interface CustomerTicketService { + + + Mono generateCustomerTicket(String accountId, String orderNumber); +} diff --git a/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/service/CustomerTicketServiceImpl.java b/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/service/CustomerTicketServiceImpl.java new file mode 100644 index 0000000..2e9047f --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/customer-service/src/main/java/com/baiye/service/CustomerTicketServiceImpl.java @@ -0,0 +1,37 @@ +package com.baiye.service; + +import com.baiye.domain.CustomerTicket; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +@Service +public class CustomerTicketServiceImpl implements CustomerTicketService{ + + private static final Logger logger = LoggerFactory.getLogger(CustomerTicketService.class); + + /** + * 典型使用案例: 从其他的两个服务拿到相应的对象进行聚合转化保存 + * + * @param accountId + * @param orderNumber + * @return + */ + @Override + public Mono generateCustomerTicket(String accountId, String orderNumber) { + logger.debug("Generate customer ticket record with account: {} and order: {}", accountId, orderNumber); + + // 设置 customerTicket - id + // fixme 正式环境不要使用 UUID + CustomerTicket customerTicket = new CustomerTicket(); + customerTicket.setId("C_" + UUID.randomUUID().toString()); + + // TODO: 2022/9/4 代码暂存 + + + return null; + } +} diff --git a/best-practice/css-webflux/reative-spring-css/message/pom.xml b/best-practice/css-webflux/reative-spring-css/message/pom.xml new file mode 100644 index 0000000..28e4da0 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/message/pom.xml @@ -0,0 +1,19 @@ + + + + reative-spring-css + org.example + 1.0-SNAPSHOT + + 4.0.0 + + message + + + 8 + 8 + + + \ No newline at end of file diff --git a/best-practice/css-webflux/reative-spring-css/order-service/pom.xml b/best-practice/css-webflux/reative-spring-css/order-service/pom.xml new file mode 100644 index 0000000..998ed9d --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/order-service/pom.xml @@ -0,0 +1,64 @@ + + + + reative-spring-css + org.example + 1.0-SNAPSHOT + + 4.0.0 + order-service + 1.0.1-RELEASE + jar + + Order Service + + + 8 + 8 + + + + + + + + + + + org.springframework.boot + spring-boot-starter-data-mongodb-reactive + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/OrderApplication.java b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/OrderApplication.java new file mode 100644 index 0000000..7909d70 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/OrderApplication.java @@ -0,0 +1,11 @@ +package com.baiye; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class OrderApplication { + public static void main(String[] args) { + SpringApplication.run(OrderApplication.class, args); + } +} diff --git a/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/controller/OrderHandler.java b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/controller/OrderHandler.java new file mode 100644 index 0000000..9af52c0 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/controller/OrderHandler.java @@ -0,0 +1,30 @@ +package com.baiye.controller; + +import com.baiye.domain.Order; +import com.baiye.service.OrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +@Configuration +public class OrderHandler { + + private final OrderService orderService; + + public OrderHandler(OrderService orderService) { + this.orderService = orderService; + } + + public Mono getOrderByOrderNumber(ServerRequest request) { + // fixme 获取参数中的 orderName 设置 - 这种最好放在 common中定义 constant + String orderNumber = request.pathVariable("orderNumber"); + + // 返回包装后的 Reactor 调用结果 + return ServerResponse + .ok() + .body(this.orderService.getOrderByOrderNumber(orderNumber), Order.class); + } + +} diff --git a/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/controller/OrderRouter.java b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/controller/OrderRouter.java new file mode 100644 index 0000000..c5e733f --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/controller/OrderRouter.java @@ -0,0 +1,21 @@ +package com.baiye.controller; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.server.*; + +@Configuration +public class OrderRouter { + + @Bean + public RouterFunction routeOrder(OrderHandler orderHandler) { + return RouterFunctions + .route(RequestPredicates + .GET("/orders/{orderNumber}") + .and(RequestPredicates.accept(MediaType.APPLICATION_JSON)), + // 这里要进行非空判断 + orderHandler::getOrderByOrderNumber + ); + } +} diff --git a/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/domain/Order.java b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/domain/Order.java new file mode 100644 index 0000000..aa7d735 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/domain/Order.java @@ -0,0 +1,49 @@ +package com.baiye.domain; + +public class Order { + + private String id; + private String orderNumber; + private String deliveryAddress; + private String goods; + + public Order() { + super(); + } + + public Order(String id, String orderNumber, String deliveryAddress, String goods) { + super(); + this.id = id; + this.orderNumber = orderNumber; + this.deliveryAddress = deliveryAddress; + this.goods = goods; + } + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + public String getOrderNumber() { + return orderNumber; + } + public void setOrderNumber(String orderNumber) { + this.orderNumber = orderNumber; + } + public String getDeliveryAddress() { + return deliveryAddress; + } + public void setDeliveryAddress(String deliveryAddress) { + this.deliveryAddress = deliveryAddress; + } + + public String getGoods() { + return goods; + } + + public void setGoods(String goods) { + this.goods = goods; + } + +} diff --git a/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/service/OrderService.java b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/service/OrderService.java new file mode 100644 index 0000000..6f82aa8 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/service/OrderService.java @@ -0,0 +1,9 @@ +package com.baiye.service; + +import com.baiye.domain.Order; +import reactor.core.publisher.Mono; + +public interface OrderService { + + Mono getOrderByOrderNumber(String orderNumber); +} diff --git a/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/service/OrderServiceImpl.java b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/service/OrderServiceImpl.java new file mode 100644 index 0000000..f15e071 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/order-service/src/main/java/com/baiye/service/OrderServiceImpl.java @@ -0,0 +1,13 @@ +package com.baiye.service; + +import com.baiye.domain.Order; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +public class OrderServiceImpl implements OrderService{ + @Override + public Mono getOrderByOrderNumber(String orderNumber) { + return null; + } +} diff --git a/best-practice/css-webflux/reative-spring-css/pom.xml b/best-practice/css-webflux/reative-spring-css/pom.xml new file mode 100644 index 0000000..82df350 --- /dev/null +++ b/best-practice/css-webflux/reative-spring-css/pom.xml @@ -0,0 +1,27 @@ + + + + dev-protocol + org.example + 1.0-SNAPSHOT + ../../../pom.xml + + 4.0.0 + reative-spring-css + pom + + + account-service + customer-service + order-service + message + + + + 8 + 8 + + + \ No newline at end of file diff --git a/fuli/jav-addr/pom.xml b/fuli/jav-addr/pom.xml new file mode 100644 index 0000000..97ce4e5 --- /dev/null +++ b/fuli/jav-addr/pom.xml @@ -0,0 +1,28 @@ + + + + dev-protocol + org.example + 1.0-SNAPSHOT + ../../pom.xml + + 4.0.0 + + jav-addr + + + 8 + 8 + + + + + cn.hutool + hutool-all + 5.7.22 + + + + \ No newline at end of file diff --git a/fuli/jav-addr/src/main/java/com.baiye/Jav.java b/fuli/jav-addr/src/main/java/com.baiye/Jav.java new file mode 100644 index 0000000..27e5b86 --- /dev/null +++ b/fuli/jav-addr/src/main/java/com.baiye/Jav.java @@ -0,0 +1,39 @@ +package com.baiye; + +import cn.hutool.core.util.StrUtil; + +import java.util.List; + +/** + * 小网站生成器 + */ +public class Jav { + + public static void main(String[] args) { + String pre = "javbus|busjav|busfan|fanbus|buscdn|cdnbus|dmmsee|seedmm|busdmm|dmmbus|javsee|seejav|avsox"; + + String end = "jav|bus|dmm|see|cdn|fan"; + + + List split = StrUtil.split(pre, "|"); + + List split1 = StrUtil.split(end, "|"); + + String dian = "."; + + for (String preIndex : split) { + + String www = "https://www"; + for (String endIndex : split1) { + StringBuilder stringBuilder = new StringBuilder() + .append(www) + .append(dian) + .append(preIndex) + .append(dian) + .append(endIndex); + System.out.println(stringBuilder); + } + } + + } +} diff --git a/pom.xml b/pom.xml index c9d995f..a1f236f 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,9 @@ longpolling/demo/demo3/dev-protocol-netty-common code-language/java/java-demo bigdata/spark/best-spark + fuli/jav-addr + spring/spring-webflux/spring-webflux-demo + best-practice/css-webflux/reative-spring-css diff --git a/spring/spring-webflux/README.md b/spring/spring-webflux/README.md new file mode 100644 index 0000000..b982b02 --- /dev/null +++ b/spring/spring-webflux/README.md @@ -0,0 +1,113 @@ +

Spring 响应式编程

+ + +# 0. 目录 + + + + +# 1. 基本概念 +- 数据流和响应式 + - 数据流就是说明全链路都是以事件的方式进行驱动的 + - 响应式编程核心特点: 不采用传统的同步调用方式处理数据, 而是由处于数据库上游的各层组件自动执行事件 + - 响应式编程: 基于事件的发布订阅机制, 使用推的方式 + - 优势: 生成事件和消费事件的过程是异步执行的,所以线程的生命周期很短,资源之间的竞争关系较少, 服务器的响应能力也就越高 +- 响应式宣言和响应式系统 + - 即时响应性(Responsive)、回弹性(Resilient)、弹性(Elastic)以及消息驱动(Message Driven)构成了响应式宣言的主体内容。 + - ![响应式宣言](pic/响应式宣言.png) + - 具备上图中各个特性的系统,就可以称为响应式系统 + +# 2. 背压机制 +- 流概念 + - 由生产者生产并由多个消费者消费的元素序列(生产者消费者模型 | 发布者订阅者模型) +- 流的处理模式 + - "拉模式": 消费者主动从生产者拉取元素 + - "推模式": 生产者将元素推送给消费者[ 资源利用率更好] +- 流量控制 + - 生产者生产数据的速率小于消费者 + - 消费者数据没有压力, 也就不需要进行流量控制 + - 生产者生产数据大于消费者消费数据 - [常见] + - 消费者可能因为无法处理过多的数据而发生崩溃 + - 常见地解决方案是 **在生产者和消费者之间加队列的形式** +- 纯推模式下的数据流量会有很多不可控的因素, 需要在推模式和拉模式之间考虑一定的平衡性从而优雅的实现流量的控制 +- 背压机制: 下游能够向上游反馈流量请求的机制 + - 如果消费者消费数据的速度赶不上生产者生产数据的速度时, 他将会持续消耗系统的资源 +- 响应式流的核心接口 +```java +// Publisher + +public interface Publisher{ + public void subscribe(Subscriber s); +} + + +// Subscriber + +public void onSubscribe(Subscriber s) // 回调方法 + +public void onNext(T t) {} // 向订阅者发送数据 + +public void onError(Throwable e) {} // 触发异常时候 + +public void onCompleted() {} // 数据流发送结束 + + +// Subscription 对象是确保生产者和消费者针对数据处理速度达成的一种动态平衡的基础, 也是流量控制中实现背压机制的关键所在 + +public interface Subscription { + void request(long var1); + + void cancel(); +} + +``` +- 业界主流的响应式开发库包括: **RxJava, Akka, Vert.x 以及 Project Reactor** + +# 3. 响应式编程应用场景 +- 数据流处理是响应式编程的一大应用场景, 流式系统的主要特点是低延迟和高吞吐 +- 网关的使用 + - 网关的作用就是用来响应前端系统的流量并将其转发到后端服务 + - Netflix Hystrix SpringCLoud Gateway 以及 SpringWebFlux + + +# 4. 基于 Spring 框架学习响应式编程 +- 响应式编程并不是只针对系统中的某一个部分组件, 而是需要适用于调用链路上的所有组件 +- 只要有一个环节不是响应式的, 那么这个环节就会出现同步阻塞 +- Spring5 提供了 WebFlux + SpringData Reactive +- WebFlux不仅包含了对创建和访问响应式HTTP端点的支持, 还可以用来实现服务器推送事件以及 WebSocket +- Spring WebFlux 需要支持异步的运行环境 + - 比如 Netty,Undertow 以及 Servlet 3.1 版本以上的 Tomcat 和 Jetty +- 非常适合开发 I/O 密集型服务 +- 不要 WebFlux和 SpringMVC混合使用, 无法保证全栈式的响应式流 +- 案例: CSS: (Customer Service System)客户服务系统 + - ![ReactiveSpringCSS架构](pic/ReactiveSpringCSS架构.png) + - 开发重点 + - Web层: 构建 RESTFUL 端点, 并通过响应式请求的WebClient客户端组件来消费这些端点 + - Service层: 核心逻辑在于完成事件处理和消息通信相关的业务场景 account-service 消息的发布者, customer-service 则是消息消费者 + - Repository层: 引入 MongoDB和Redis两款支持响应式流的 NoSQL 数据库, MongoDB为各个服务存储业务数据, Redis主要用于在 customer-service 中 + - ![ReactiveSpringCSS技术组件图](pic/ReactiveSpringCSS技术组件图.png) + +# 5. 了解 Reactor +- RxJava诞生的更早, 但是 Reactor 更有前途 +- 使用 弹珠图来说明 响应式编程的策略(Marble Diagram) + +# 6. 使用 Flux 和 Mono 构建响应式数据流 +- Flux 创建 + - 基于各种工厂模式的静态创建方法 + - just() range() interval() 以及各种以 from- 为前缀的方法组等 + - 采用编程方式动态创建Flux + - +- 注解方式进行编码 + - 基于Java注解的方式进行编码, 编程模型和 Spring MVC 一致 + - 基于函数式编程模型 + + + + + + + + + + + diff --git a/spring/spring-webflux/pic/ReactiveSpringCSS技术组件图.png b/spring/spring-webflux/pic/ReactiveSpringCSS技术组件图.png new file mode 100644 index 0000000..483a0af Binary files /dev/null and b/spring/spring-webflux/pic/ReactiveSpringCSS技术组件图.png differ diff --git a/spring/spring-webflux/pic/ReactiveSpringCSS架构.png b/spring/spring-webflux/pic/ReactiveSpringCSS架构.png new file mode 100644 index 0000000..555f800 Binary files /dev/null and b/spring/spring-webflux/pic/ReactiveSpringCSS架构.png differ diff --git a/spring/spring-webflux/pic/响应式宣言.png b/spring/spring-webflux/pic/响应式宣言.png new file mode 100644 index 0000000..39a0eda Binary files /dev/null and b/spring/spring-webflux/pic/响应式宣言.png differ diff --git a/spring/spring-webflux/spring-webflux-demo/pom.xml b/spring/spring-webflux/spring-webflux-demo/pom.xml new file mode 100644 index 0000000..34a51f6 --- /dev/null +++ b/spring/spring-webflux/spring-webflux-demo/pom.xml @@ -0,0 +1,78 @@ + + + + dev-protocol + org.example + 1.0-SNAPSHOT + ../../../pom.xml + + 4.0.0 + + spring-webflux-demo + + + 8 + 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.projectreactor + reactor-test + test + + + + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/spring/spring-webflux/spring-webflux-demo/src/main/java/com/baiye/HelloWebFluxApplication.java b/spring/spring-webflux/spring-webflux-demo/src/main/java/com/baiye/HelloWebFluxApplication.java new file mode 100644 index 0000000..addbe1f --- /dev/null +++ b/spring/spring-webflux/spring-webflux-demo/src/main/java/com/baiye/HelloWebFluxApplication.java @@ -0,0 +1,16 @@ +package com.baiye; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 启动入口 + * + * @author q + */ +@SpringBootApplication +public class HelloWebFluxApplication { + public static void main(String[] args) { + SpringApplication.run(HelloWebFluxApplication.class, args); + } +} diff --git a/spring/spring-webflux/spring-webflux-demo/src/main/java/com/baiye/controller/HelloWebFluxController.java b/spring/spring-webflux/spring-webflux-demo/src/main/java/com/baiye/controller/HelloWebFluxController.java new file mode 100644 index 0000000..914f8b8 --- /dev/null +++ b/spring/spring-webflux/spring-webflux-demo/src/main/java/com/baiye/controller/HelloWebFluxController.java @@ -0,0 +1,14 @@ +package com.baiye.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +@RestController +public class HelloWebFluxController { + + @GetMapping("/") + public Mono hello() { + return Mono.just("Hello World for WebFlux !"); + } +}