责任链模式 多条链路时 spring单例 造成的深坑
https://mp.weixin.qq.com/s/ipXPMtPawDdESMJYrYthcQ
一)线上事故:
催收系统每日自动分配案件时一直正常,突然某一天(2018-3-27)以后 案件分配不均匀,一系列追踪下查到原因是责任链 有一环 未被执行(kibana上当天2018-3-27 以后 未查看相应的日志记录) ,很奇怪 ,重启服务后 第二天 结果恢复正常
(二)分析问题:
分析 具体的催收分案业务 , 有手动分案(责任链模式)和每日自动分案(责任链模式)两种情形,未被执行的一环正好是 手动分案 相比 自动分案 缺少的一环
(三)问题猜想 :
查看 日志发现 当天 确实 存在手动分案的操作记录 ,猜想是手动分案 影响了 自动分案的功能
(四)查看代码,分析问题
@Service
public class DistributionHandlerHolder implements IDistributionHandlerHolder {
/**
* 自动分案,逻辑最完备
*/
private AbstractHandler autoDistribution;
/**
* 手动分案,不记录上次催收人以及下次催收人等
*/
private AbstractHandler manualDistribution;
@Override
public AbstractHandler getAutoExecuteHandler() {
if(autoDistribution == null) {
synchronized(this) {
if(autoDistribution == null) {
createAutoExecuteHandler();
}
}
}
return autoDistribution;
}
@Override
public AbstractHandler getManualExecuteHandler() {
if(manualDistribution == null) {
synchronized(this) {
if(manualDistribution == null) {
createManualExecuteHandler();
}
}
}
return manualDistribution;
}
private void createAutoExecuteHandler() {
AbstractHandler autoStart = null;
AbstractHandler autoPre = null;
for(AutoDistributionEnum distributionEnum : AutoDistributionEnum.values()) {
AbstractHandler handler = ApplicationContextHolder.getBean(distributionEnum.getBeanName(), AbstractHandler.class);
if(autoPre != null) {
autoPre.setNextHandler(handler);
}
if(autoStart == null) {
autoStart = handler;
}
autoPre = handler;
}
autoDistribution = autoStart;
}
private void createManualExecuteHandler() {
AbstractHandler manualStart = null;
AbstractHandler manualPre = null;
for(ManualDistributionEnum distributionEnum : ManualDistributionEnum.values()) {
AbstractHandler handler = ApplicationContextHolder.getBean(distributionEnum.getBeanName(), AbstractHandler.class);
if(manualPre != null) {
manualPre.setNextHandler(handler);
}
if(manualStart == null) {
manualStart = handler;
}
manualPre = handler;
}
manualDistribution = manualStart;
}
}
@Slf4j
public abstract class AbstractHandler {
protected AbstractHandler nextHandler;
public void setNextHandler(AbstractHandler nextHandler) {
this.nextHandler = nextHandler;
}
}
@Component("distributionUserSortHandler")
@Slf4j
public class UserSortHandler extends AbstractHandler {
@Autowired
private IOrderService orderService;
@Override
public void execute(DistributionRequest request, DistributionResponse response) {
nextHandler.execute(request, response);
}
}
1、大体上看没有问题,
手动分案和自动分案是两条完全不同的
责任链创建过程
2、仔细观察是每个责任链 是单例模式 ,没有标记@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 注解 ,和大脑印象中代码不符合
3、仔细分析 : (1)自动分案 走 1-》2-》3-》4
(2)手动分案走 1-》2-》4
(3)先自动分案 ,后手动分案,造成 自动分案
被替换成 1-》2-》4,造成 3链缺失
(四) 解决方案:
每个责任链上加上@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)注解,造成
AbstractHandler handler =
ApplicationContextHolder.getBean(distributionEnum.getBeanName(), AbstractHandler.class);获取时获取到不同的对象 ,而不是spring单例对象
(五) 归纳总结:
spring 单例 最好无状态,责任链 的每一环必有状态(指向下一环),因为存在多条链路(多种业务情况)
所以每一环应该定义成多例(最好多例),否则就造成如上的线程间不安全的问题。
责任链模式 多条链路时 spring单例 造成的深坑相关推荐
- 用三国演义解读:责任链模式
故事 前两天,没事又刷了一遍三国演义,看到关羽身在曹营心在汉,听说刘备在袁绍那里,然后就上演了"过五关,斩六将". 关羽过五关斩六将主要内容: 第一关,东岭关,斩守将孔秀.东岭关, ...
- 三国演义:责任链模式
故事 前两天,没事又刷了一遍三国演义,看到关羽身在曹营心在汉,听说刘备在袁绍那里,然后就上演了"过五关,斩六将". 关羽过五关斩六将主要内容: 第一关,东岭关,斩守将孔秀. 东岭关 ...
- 设计模式 - 责任链模式
故事 前两天,没事又刷了一遍三国演义,看到关羽身在曹营心在汉,听说刘备在袁绍那里,然后就上演了"过五关,斩六将". 关羽过五关斩六将主要内容: 第一关,东岭关,斩守将孔秀. 东岭关 ...
- 责任链模式Java+Spring实现
业务场景 一般的操作校验接口有参数校验.安全校验.黑名单校验.操作规则等等. 问题 常见同步编写code,校验失败return,代码链路较长,修改不符合开闭原则. 责任链模式定义 责任链模式为请求创建 ...
- Spring中如何使用责任链模式
2019独角兽企业重金招聘Python工程师标准>>> 关于责任链模式,其有两种形式,一种是通过外部调用的方式对链的各个节点调用进行控制,从而进行链的各个节点之间的切换:另一种是链的 ...
- spring AOP原理分析:静态代理;JDK实现接口动态代理;Cglib继承父类代理;SpringAop的责任链模式调用
普通静态代理 代理类和真实类都需要实现同一个接口 接口 package com.fchan.layui.represent.service; /*** 静态代理demo*/ public interf ...
- 设计模式(四)责任链模式——责任链模式结构
定义 责任链是行为型设计模式的一种,通过前一个处理者记录下一个处理者的方式形成一条处理链.客户端在调用时只需要将请求传递到责任上即可,无需关注链路中的具体的传递过程.而链路中内部的处理,是按照前一个处 ...
- 【深入设计模式】责任链模式—责任链模式及责任链模式在源码中的应用
文章目录 1. 责任链模式 1.1 责任链模式简介 1.2 责任链模式结构 1.3 责任链模式示例 2. 责任链模式在源码中的应用 2.1 Servlet 中的责任链模式 2.2 Spring 中的责 ...
- 设计模式-责任链模式~晚霞
Chain of Responsibility Pattern Title Module Category Tags Chain of Responsibility chain-of-responsi ...
最新文章
- 互联网黄金十年的黄昏——是人工智能的黎明还是裁员的长夜
- vmware 利用镜像 配置yum本地源
- MR8M CANCEL INVOICE后为什么要手工去FI清帐
- Note cancel request的实现原理
- AngularJS控制器和过滤器学习(三)
- 探索Windows命令行系列(7):通过命令编译C#类和Java类
- XSS-Payloads集合
- 第 89 章 Hardware
- sklearn svm 调参_用 Grid Search 对 SVM 进行调参
- 打车日记 - 原年人念念不忘的茄汁大虾
- dependency标签
- html文件下载时的header设置
- 无法在驱动器0分区上安装windows解决方法
- wex5 导入mysql_Wex5铛铛开发环境搭建步骤
- http://nianjian.xiaze.com/tags.php?/%E4%B8%AD%E5%9B%BD%E7%B2%89%E4%BD%93%E5%B7%A5%E4%B8%9A%E5%B9%B4%
- 计算机自定义桌面设置在哪里设置,如何在windows10桌面设置自定义图片?查看方法...
- maven pom.xml解析、命令说明、依赖传递、继承、聚合、properties、build、依赖范围、版本仲裁、profile
- Axure8.0基础教程 一
- iOS小知识:如何使用教育商店购买Apple M1 Max
- 苹果 macOS 13 开发者预览版 Beta 11(内部版本号:22A5373b)发布