简单用例
现有一开发场景,要求设计一个集团采购物品,不同金额交由不同领导审批的流程
现有三级领导,金额在5000以下的,由部门领导审批;金额在10000以下的由院校级领导审批;金额在10000以上的,由校级领导审批。虽然使用 if-else 也能实现改功能,但是代码的可读性、可扩展性差,使用责任链设计模式,是面向对象的思维方式,符合“开闭原则”,具体实现的代码如下:
责任链调用发起者
public static void main(String[] args) {
PurchaseRequest purchaseRequest = new PurchaseRequest(1, 5001, 11);
DepartmentApprover departmentApprover = new DepartmentApprover("部门审批者 张xx");
CollegeApprover collegeApprover = new CollegeApprover("院系审批者 李xx");
SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("校长审批 王xx");
//设置责任链的下一个处理类(该段设置chain的逻辑,也可以在不同的approver子类中设置,但缺点是不易管理)
departmentApprover.nextApprover=collegeApprover;
collegeApprover.nextApprover=schoolMasterApprover;
//为实现调用chain中任意一个处理类,都可以得到正确的结果,在这里构建一个环形链表
schoolMasterApprover.nextApprover=departmentApprover;
schoolMasterApprover.processRequest(purchaseRequest);//输出:请求编号:11 当前审批人名:院系审批者 李xx
}
批准人抽象类
public abstract class Approver {
Approver nextApprover;//下一个处理者
String name;
public Approver(String name) {
this.name = name;
}
//交由子类去完善处理审批的逻辑
public abstract void processRequest(PurchaseRequest purchaseRequest);
}
部门审批者、院系审批者、校长审批实现类
public class DepartmentApprover extends Approver{
public DepartmentApprover(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if(purchaseRequest.price<=5000f){
System.out.println("请求编号:" + purchaseRequest.id + " 当前审批人名:" + this.name);
}else {
nextApprover.processRequest(purchaseRequest);
}
}
}
public class CollegeApprover extends Approver {
public CollegeApprover(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if (purchaseRequest.price > 5000f && purchaseRequest.price <= 10000) {
System.out.println("请求编号:" + purchaseRequest.id + " 当前审批人名:" + this.name);
} else {
nextApprover.processRequest(purchaseRequest);
}
}
}
public class SchoolMasterApprover extends Approver {
public SchoolMasterApprover(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest purchaseRequest) {
if(purchaseRequest.price>10000f){
System.out.println("请求编号:" + purchaseRequest.id + " 当前审批人名:" + this.name);
}else {
nextApprover.processRequest(purchaseRequest);
}
}
}
使用责任链的注意事项和细节
- 降低了流程中,调用链与链中某一节点执行逻辑的耦合度,提高了系统的灵活性
- 当链中节点比较多时,系统的性能会受到影响,因此,可以考虑控制最长链节点。
设计模式是一种思想,在不同的地方,实现的方式可能不同,但大致的思想都是一致的,都是为了提高扩展性,可读性等原因。
实际生产用例
场景
- 一个档案文件可能会经历移交、归档、长期保持环节,在经历不同的环节时需要执行四性检测
- 在对一个档案文件的四性检测中,需要对真实、完整、可靠、安全性进行检测,且在四性中包含了103个检测项目。
- 四性检测对每一个文件都需要过,检测项目按具体需求进行检测。
实现
整体实现思路:
将四性的类通过执行链串起来,103个检测项目方法在对应的四性里,期间的执行结果通过 DetectionBuilder 类来保存。对于检测项目,通过反射去调用。
//detectionBuilder 中包含本次检测需要的多个信息
DetectionBuilder detectionBuilder = new DetectionBuilder( lists, dataInfo.getId(), arcfile, DetectionSegmentType.移交,
adjunctFileInfos, fourDetectionRecordService.getLastDetection( dataInfo.getId(), DetectionSegmentType.移交 ) );
//调用入口。
Detection detection = FourDetectionFactory.getHandler().detectionChain( detectionBuilder ).getDetection();
FourDetectionFactory 类,获取、设置链顺序:
public class FourDetectionFactory {
/**
* 一个handler头
*/
private static AbstractDetectionHandler allHandler;
public static HashMap<String, String> codeAndMethodName;
//初始化detection_code与项目方法名的对应
static {
codeAndMethodName = new HashMap((int) (103 / 0.75 + 1));
codeAndMethodName.put("GD-1-1", "doFixityInformationDetection");
……
codeAndMethodName.put("GD-4-7", "doSysProcessSafety");
codeAndMethodName.put("YJ-1-1", "doFixityInformationDetection");
……
codeAndMethodName.put("YJ-4-7", "doSysProcessSafety");
codeAndMethodName.put("BC-1-1", "doFixityInformationDetection");
……
codeAndMethodName.put("BC-4-9", "doSaveEnvironment");
}
public static synchronized AbstractDetectionHandler getHandler() {
if (allHandler != null) {
return allHandler;
}
// 通过接口从IOC容器中获取对应的实现类
DetectionService realDetectionService = SpringUtils.getBean(RealDetectionService.class);
DetectionService completeDetectionService = SpringUtils.getBean(CompleteDetectionService.class);
DetectionService availableDetectionService = SpringUtils.getBean(AvailableDetectionService.class);
DetectionService safeDetectionService = SpringUtils.getBean(SafeDetectionService.class);
if (realDetectionService == null) {
throw new IllegalArgumentException("error: realDetectionService bean 注册失败!");
}
if (completeDetectionService == null) {
throw new IllegalArgumentException("error: completeDetectionService bean 注册失败!");
}
if (availableDetectionService == null) {
throw new IllegalArgumentException("error: availableDetectionService bean 注册失败!");
}
if (safeDetectionService == null) {
throw new IllegalArgumentException("error: safeDetectionService bean 注册失败!");
}
allHandler = new AbstractDetectionHandler(null);
AbstractDetectionHandler realHandler = new AbstractDetectionHandler(realDetectionService);
AbstractDetectionHandler completeHandler = new AbstractDetectionHandler(completeDetectionService);
AbstractDetectionHandler availableHandler = new AbstractDetectionHandler(availableDetectionService);
AbstractDetectionHandler safeHandler = new AbstractDetectionHandler(safeDetectionService);
allHandler.setNextHandler(realHandler);
realHandler.setNextHandler(completeHandler);
completeHandler.setNextHandler(availableHandler);
availableHandler.setNextHandler(safeHandler);
return allHandler;
}
}
AbstractDetectionHandler 具体链的调用方法,其中 detectionService 在不同的 AbstractDetectionHandler 实例中赋予了不同的值:
public class AbstractDetectionHandler {
// 责任链中的下一个元素
protected AbstractDetectionHandler nextHandler;
// detectionService是链中四个对象的父接口
protected DetectionService detectionService;
public void setNextHandler(AbstractDetectionHandler handler) {
this.nextHandler = handler;
}
// 四性检测开始执行,使用责任链模式将任务串联起来,递归调用
public DetectionBuilder detectionChain(DetectionBuilder detectionBuilder) {
try {
detectionBuilder = doDetection(detectionBuilder);
if (nextHandler != null) {
detectionBuilder = nextHandler.detectionChain(detectionBuilder);
}
}catch (Exception e){
e.printStackTrace();
}
return detectionBuilder;
}
//当前detectionBuilder需要执行的检测环节
private DetectionBuilder doDetection(DetectionBuilder detectionBuilder) {
DetectionSegmentType code = detectionBuilder.getDetection().getCode();
if (code == null) {
throw new IllegalArgumentException("参数缺失");
}
if (this.detectionService != null) {
switch (code) {
case 归档:
detectionBuilder = detectionService.doPostDetection(detectionBuilder);
break;
case 移交:
detectionBuilder = detectionService.doMoveDetection(detectionBuilder);
break;
case 长期保存:
detectionBuilder = detectionService.doSaveDetection(detectionBuilder);
break;
}
}
return detectionBuilder;
}
public AbstractDetectionHandler(DetectionService detectionService) {
this.detectionService = detectionService;
}
}
AvailableDetectionServiceImpl 是 detectionService 的一个子类,在 AbstractDetectionHandler 类的 doDetection() 中调用,下面截取了类中的主要逻辑方法。
- doPostDetection() 方法在 detectionService 的其他三个子类中都有实现,因为三个环节中都需要执行对应的四性检测。
- doNeedDetection() 方法是为了实现按需执行检测项目(103个检测项不一定全部执行)。由于该方法使用的是反射调用类中的方法(即检测项目),故使用注解注入需要的实现类(涉及到 IOC 中循环注入可参考博主该文章)。
@Service
public class AvailableDetectionServiceImpl implements implements AvailableDetectionService {
@Resource
private RealDetectionService realDetectionService;
@Resource
private CompleteDetectionService completeDetectionService;
@Resource
private AvailableDetectionService availableDetectionService;
@Resource
private SafeDetectionService safeDetectionService;
/**
* 归档 可用性检测
*/
@Override
public DetectionBuilder doPostDetection(DetectionBuilder detectionBuilder) {
doNeedDetection(fourDetection,detectionBuilder);
return detectionBuilder;
}
/**
* 在环节和四性下检测需要的检测项目
*/
public void doNeedDetection(String fourDetection, DetectionBuilder detectionBuilder) {
//按拿到要检测的项目;反射调用对应的方法
//通过文件的档案库id拿到检查项目,如果没有该级,则向上递归一级
String orgId = detectionBuilder.getDetection().getArcfile().getOwnOrgId();
String generalId = detectionBuilder.getDetection().getArcfile().getGeneralId();
String repositoryId = detectionBuilder.getDetection().getArcfile().getRepositoryId();
List<String> orgGeneralRepository = new ArrayList<>();
if(StringUtils.isNotBlank(repositoryId)){
orgGeneralRepository.add(repositoryId);
}else if(StringUtils.isNotBlank(generalId)){
orgGeneralRepository.add(generalId);
}else {
orgGeneralRepository.add(orgId);
}
DetectionSegmentType nowLinkType = detectionBuilder.getDetection().getCode();
//将拿到该文件当前环节、当前四性下的检测项目
List<FourDetection> fourDetectionList = fourDetectionServiceImpl.getFourDetectionByGeneralId(orgGeneralRepository, nowLinkType.getValue(), fourDetection);
//遍历调用方法
fourDetectionList.forEach(e -> {
//判断该项目是否属于当前的环节
if (e == null || !nowLinkType.getValue().equals(e.getLinkType())) {
return;
}
DetectionService service = null;
//自动注入的都将为成员变量在反射后,都将为null,故需要修改为从ioc中获取对应的对象
DetectionClass detectionClass = (DetectionClass) EnumService.getEnum(DetectionClass.class, e.getFourDetection());
switch (detectionClass) {
case 真实性:
service = realDetectionService;
break;
case 完整性:
service = completeDetectionService;
break;
case 可用性:
service = availableDetectionService;
break;
case 安全性:
service = safeDetectionService;
break;
}
if (service == null) {
return;
}
Class<? extends DetectionService> aClass = service.getClass();
try {
String methodName = FourDetectionFactory.codeAndMethodName.get(e.getDetectionCode());//是否包含改方法的判断doElectronicDocumentsDetection
Method test = aClass.getDeclaredMethod(methodName, DetectionBuilder.class);
test.invoke(service, detectionBuilder);
} catch (Exception a) {
a.printStackTrace();
}
});
}
}
责任链在 Spring MVC 的 HandlerExecutionChain 中的应用源码解析
在 Spring MVC 的 DispatcherServlet 类中,有如下的主要代码逻辑:
doDispatch方法中,构建了 interceptor 执行链,将请求分配给 preHandle 执行,当 preHandle 方法返回为 false时,会调用到 afterCompletion 执行,最后调用 postHandle 方法。
protected void doDispatch (HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerExecutionChain mappedHandler = null;
mappedHandler = getHandler(processedRequest);
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//当上面的 applyPreHandle 返回false时,继续向下执行到
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
//调用拦截器的 interceptor.preHandle
boolean applyPreHandle (HttpServletRequest request, HttpServletResponse response) {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;*}
}
return true;
}
void triggerAfterCompletion (HttpServletRequest request, HttpServletResponse response,Exception ex){
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
}
//调用拦截器的 interceptor.postHandle
void applyPostHandle (HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv){
HandlerInterceptor interceptor = interceptors[i];
interceptor.postHandle(request, response, this.handler, mv);
}
- HandlerExecutionChain 本身不会执行 interceptor 的逻辑,只是将请求分配给 chain 上注册的 interceptor 执行;
- HandlerExecutionChain 维护了 HandlerInterceptor 的集合。
监听器(listener)、过滤器(filter)、拦截器(interceptor)的执行顺序参考
SpingMvc的整体执行流程参考