哈尔滨网站制作软件,微信小程序分销,网站开发下载功能如何实现,汕头seo课程培训任何体系结构决策都需要权衡。 如果您决定采用反应式#xff0c;也没有什么不同#xff0c;例如#xff0c;一方面使用反应式流实现几乎可以立即获得更好的资源利用率#xff0c;但另一方面会使调试更加困难。 引入反应式库也对您的域产生巨大影响#xff0c;您的域将不再… 任何体系结构决策都需要权衡。 如果您决定采用反应式也没有什么不同例如一方面使用反应式流实现几乎可以立即获得更好的资源利用率但另一方面会使调试更加困难。 引入反应式库也对您的域产生巨大影响您的域将不再仅在Payment Order或Customer方面说话反应式术语将破解FluxPayment FluxOrder MonoCustomer 或ObservablePayment FlowableOrder SingleCustomer或您选择的库提供的任何Reactive Streams发布者。 这种折衷很快就变得很明显但是您可能会猜想并非所有的折衷都会如此明显– 泄漏抽象定律保证了这一点。 反应性库使更改线程上下文变得轻而易举。 您可以轻松地订阅一个调度程序然后在另一个调度程序上执行一部分操作员链最后跳到完全不同的调度程序上。 只要不涉及线程局部状态这种从一个线程到另一个线程的跳转就可以工作-尽管它支持服务的关键部分例如安全性事务但通常不会每天处理该状态 多租户。 当您的技术堆栈中隐藏良好的部分取决于线程局部状态时更改线程上下文会导致棘手的错误定位。 让我通过一个简单的示例演示该问题 private static final Logger LOG LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static final String SESSION_ID session-id;GetMapping(documents/{id})
MonoString getDocument(PathVariable(id) String documentId) {MDC.put(SESSION_ID, UUID.randomUUID().toString());LOG.info(Requested document[id{}], documentId);return Mono.just(Lorem ipsum).map(doc - {LOG.debug(Sanitizing document[id{}], documentId);return doc.trim();});
} 使用MDC.put(SESSION_ID, UUID.randomUUID().toString())我们将会话session-id放入基础日志库的映射诊断上下文中 以便稍后进行登录。 让我们以自动为我们记录session-id的方式配置记录模式 logging.pattern.console[%-28thread] [%-36mdc{session-id}] - %-5level - %msg%n 当我们通过请求 curl localhost:8080/documents/42 访问公开的服务时我们将看到session-id出现在日志条目中 [reactor-http-server-epoll-10] [00c4b05f-a6ee-4a7d-9f92-d9d53dbbb9d0] - INFO - Requested document[id42]
[reactor-http-server-epoll-10] [00c4b05f-a6ee-4a7d-9f92-d9d53dbbb9d0] - DEBUG - Sanitizing document[id42] 如果在将session-id放入MDC之后切换执行上下文例如通过预订不同的调度程序情况将发生变化 GetMapping(documents/{id})
MonoString getDocument(PathVariable(id) String documentId) {MDC.put(SESSION_ID, UUID.randomUUID().toString());LOG.info(Requested document[id{}], documentId);return Mono.just(Lorem ipsum).map(doc - {LOG.debug(Sanitizing document[id{}], documentId);return doc.trim();}).subscribeOn(Schedulers.elastic()); // dont use schedulers with unbounded thread pool in production
} 执行上下文更改后我们将注意到该调度程序调度的操作员记录的日志条目中缺少session-id [reactor-http-server-epoll-10] [c2ceae03-593e-4fb3-bbfa-bc4970322e44] - INFO - Requested document[id42]
[elastic-2 ] [ ] - DEBUG - Sanitizing document[id42] 您可能会猜到我们正在使用的日志记录库内部深处隐藏着一些ThreadLocal 。 一些Reactive Streams实现提供了允许将上下文数据提供给操作员的机制例如Project Reactor提供订户上下文 GetMapping(documents/{id})
MonoString getDocument4(PathVariable(id) String documentId) {String sessionId UUID.randomUUID().toString();MDC.put(SESSION_ID, sessionId);LOG.info(Requested document[id{}], documentId);return Mono.just(Lorem ipsum).zipWith(Mono.subscriberContext()).map(docAndCtxTuple - {try(MDC.MDCCloseable mdc MDC.putCloseable(SESSION_ID, docAndCtxTuple.getT2().get(SESSION_ID))) {LOG.debug(Sanitizing document[id{}], documentId);return docAndCtxTuple.getT1().trim();}}).subscriberContext(Context.of(SESSION_ID, sessionId)).subscribeOn(Schedulers.elastic()); // dont use schedulers with unbounded thread pool in production
} 当然使数据可用只是故事的一部分。 一旦我们提供了session-id subscriberContext(Context.of(SESSION_ID, sessionId)) 我们不仅必须检索它还必须将其附加到线程上下文中并且由于调度程序可以自由地记住自己所以请自己清理一下。重用线程。 提出的实现会带回session-id [reactor-http-server-epoll-10] [24351524-f105-4746-8e06-b165036d02e6] - INFO - Requested document[id42]
[elastic-2 ] [24351524-f105-4746-8e06-b165036d02e6] - DEBUG - Sanitizing document[id42] 但是使它起作用的代码太复杂太具有侵入性以致于在大多数代码库中都不会张开双臂来欢迎它尤其是当它最终散布在整个代码库中时。 我很乐意通过为该问题提供一个简单的解决方案来结束本博文但我尚未偶然发现这样的问题现在我们需要使用这样更复杂更具侵入性的解决方案同时还要尝试解决这种复杂性从以业务为中心的软件部分到基础设施部分如果可能还可以直接到库本身。 翻译自: https://www.javacodegeeks.com/2018/09/thread-local-state-availability-in-reactive-services.html