什么是责任
假设有A,B,C,D四个类按照某种顺序排序,它们都是处理一组类似的业务场景(我们项目核销场景),它们根据需求判断这件事该不该自己处理,如果该类处理不了就传递到下一个类,直到找到能够处理这件事情类或没有类能够处理这件事的为止。
具体实现
先看一幅实现类结构图:
ChainBus为统一去执行该链中的方法的类,ChainHub为统一存储链中的类,ChainRegister为一个注册器,通过该方法将方法注册到ChainHub中。
package cn.gw.common.chain;
import java.io.Serializable;
/**
* @author gaowu
* @date 2020/7/24 19:24
*/
public interface IChain extends Serializable {
}
excute方法的参数bean必须实现的类(往下看会知道)。
package cn.gw.common.chain;
import cn.gw.core.model.Resp;
/**
* @author gaowu
* @date 2020/7/24 19:27
*/
public interface IChainHandler<T extends IChain> {
Integer order();
Resp execute(T t);
}
如果一个类需要成为一个Chain,则需要实现该方法IChainHandler,Order为类的排序,execute为业务逻辑代码。注:相同一组的链中的方法,如支付,他们的参数是相同的,如支付场景(OrderPayChian),则excute方法参数为OrderPayChain。
package cn.gw.common.chain;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 存储责任链的类
*
* @author gaowu
* @date 2020/7/24 19:23
*/
public class ChainHub {
private static Map<Class, List<IChainHandler>> chainHandlersMap = new HashMap<>(16);
public static void register(Class<? extends IChain> clazz, IChainHandler handler) {
chainHandlersMap.computeIfAbsent(clazz, val -> new ArrayList<>()).add(handler);
}
public static List<IChainHandler> getChainHandlersByClass(Class<? extends IChain> clazz) {
List<IChainHandler> handlers = chainHandlersMap.get(clazz);
return handlers == null ? new ArrayList<>() : handlers;
}
public static Map<Class, List<IChainHandler>> getChainHandlersMap() {
return chainHandlersMap;
}
}
ChainHub为统一存储链式方法的类,按照execute中的参数分组,如:参数分别为OneChian与TwoChain的方法则为不同的链,应该分别存储到不同的List中。
package cn.gw.common.chain;
import cn.gw.core.model.Resp;
/**
* @author gaowu
* @date 2020/7/24 20:11
*/
public interface IChainBus<T extends IChain> {
Resp apply(T t);
}
ChainBus的接口,返回类型为Resp(可自定义一个统一的返回类型),传入参数为实现IChian的Bean。
package cn.gw.common.chain;
import cn.gw.core.exception.BaseException;
import cn.gw.core.model.HttpCodeEnum;
import cn.gw.core.model.Resp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 责任链的执行器
*
* @author gaowu
* @date 2020/7/24 19:23
*/
@Component
public class ChainBus implements IChainBus<IChain> {
private Logger log = LoggerFactory.getLogger(ChainBus.class);
@Override
public Resp apply(IChain iChain) {
List<IChainHandler> handlers = ChainHub.getChainHandlersByClass(iChain.getClass());
Resp result = null;
for (IChainHandler handler : handlers) {
try {
result = handler.execute(iChain);
} catch (Exception ex) {
return buildFailResult(ex);
}
// result不为空说明handler,execute执行成功
if (result != null) {
break;
}
}
if (result == null || result.getCode() == null) {
return Resp.fail("无法执行该请求!");
}
return result;
}
private Resp buildFailResult(Exception ex) {
log.error(ex.getMessage(), ex);
HttpCodeEnum code = HttpCodeEnum.INTERNAL_SERVER_ERROR;
if (ex instanceof BaseException) {
code = ((BaseException) ex).getCode();
}
return Resp.fail(code, ex.getMessage());
}
}
ChainBus,统一去执行该链中的方法的类,根据参数获取ChainHub存储的该类型的所有的方法,依次执行,若该类有返回值证明该方法执行成功,就不往后执行,若执行到最后方法还是无法执行,则直接抛异常或者返回一个特定的错误值。
package cn.gw.common.chain;
import java.lang.reflect.Method;
/**
* 责任链注册器
*
* @author gaowu
* @date 2020/7/24 20:20
*/
public class ChainRegister {
private static final String EXECUTE_METHOD = "execute";
public static void doRegistration(IChainHandler iChainHandler) {
Class<? extends IChain> clazz = getIChainClassByHandlerClass(iChainHandler.getClass());
if (clazz != null) {
ChainHub.register(clazz, iChainHandler);
}
}
private static Class<? extends IChain> getIChainClassByHandlerClass(Class<?> clazz) {
// try {
// Method executeMethod = clazz.getDeclaredMethod(EXECUTE_METHOD, IChain.class, IChainBus.class);
// return getExecuteMethodParamsType(executeMethod);
// } catch (NoSuchMethodException e) {
// return null;
// }
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (EXECUTE_METHOD.equals(method.getName()) && !method.isBridge()) {
return getExecuteMethodParamsType(method);
}
}
return null;
}
private static Class<? extends IChain> getExecuteMethodParamsType(Method method) {
Class<?>[] exeParams = method.getParameterTypes();
if (exeParams.length == 0) {
return null;
}
for (Class<?> clazz : exeParams) {
if (IChain.class.isAssignableFrom(clazz)) {
return (Class<? extends IChain>) clazz;
}
}
return null;
}
}
ChainRegister责任链的注册器,通过该类的doRegistration方法,将实现了IChainHandler接口方法,获取execute方法参数的class,存储到ChainHub中的chainHandlersMap中。
package cn.gw.app.config;
import cn.gw.common.chain.ChainRegister;
import cn.gw.common.chain.IChainHandler;
import cn.gw.common.helper.ApplicationContextHelper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/**
* @author gaowu
* @date 2020/5/1 2:40
*/
@Configuration
public class BootStrap {
@Bean
public void initChain() {
List<IChainHandler> iChainHandlers = new ArrayList<>(ApplicationContextHelper.getBeansOfType(IChainHandler.class).values());
iChainHandlers.sort(Comparator.comparing(IChainHandler::order));
iChainHandlers.forEach(iChainHandler -> {
ChainRegister.doRegistration(iChainHandler);
});
}
}
initChain获取Spring容器的IChainHandler,根据他们的Oder排序,依次通过注册器注册。以上就是所有责任链类的实现,下面就是责任链具体的使用例子。
package cn.gw.app.chain.newc;
import cn.gw.common.chain.IChain;
import lombok.Data;
/**
* @author gaowu
* @date 2020/7/24 20:52
*/
@Data
public class OneChain implements IChain {
private String name;
}
package cn.gw.app.chain.newc;
import cn.gw.common.chain.IChainHandler;
import cn.gw.core.exception.ServiceException;
import cn.gw.core.model.Resp;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author gaowu
* @date 2020/7/24 20:52
*/
@Component
public class OneFistChainHandler implements IChainHandler<OneChain> {
@Override
public Integer order() {
return 0;
}
@Override
public Resp execute(OneChain oneChain) {
String name = oneChain.getName();
if ("aaa".equals(name)) {
System.out.println("OneFistChainHandler -> " + name );
if (true){
throw new ServiceException("bad request");
}
Map<String, String> reslut = new HashMap<>(2);
reslut.put("name", name);
return Resp.ok(reslut);
}
return null;
}
}
package cn.gw.app.chain.newc;
import cn.gw.common.chain.IChainHandler;
import cn.gw.core.model.Resp;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author gaowu
* @date 2020/7/24 20:57
*/
@Component
public class OneSecondChainHandler implements IChainHandler<OneChain> {
@Override
public Integer order() {
return 10;
}
@Override
public Resp execute(OneChain oneChain) {
String name = oneChain.getName();
if ("bbb".equals(name)) {
System.out.println("OneSecondChainHandler -> " + name);
Map<String, String> reslut = new HashMap<>(2);
reslut.put("name", name);
reslut.put("name++", name);
return Resp.ok(reslut);
}
return null;
}
}
上面为一组参数为OneChain的责任链。
@IgnoreAuth
@PostMapping(value = "/newChain")
public Resp tetNewChain(@RequestBody OneChain chain) {
return iChainBus.apply(chain);
}
测试责任链是否正常执行。
正常数据测试。
测试execute方法有异常的情况是否能捕捉成功。
测试该链中没有类执行该业务场景,是否正常。以上测试都能说明该链的基本设计没毛病,如果更好的建议欢迎留言。