摘要:责任链模式属于行为型模式的一种,将请求沿着一条链传递,直到该链上的某个对象处理它为止。责任链模式通过将请求和处理分离开来,以进行解耦。源码分析我们经常使用的就使用到了责任链模式,创建一个除了要在应用中做相应配置外,还需要实现接口。
概述</>复制代码
责任链模式(Chain Of Responsibility Pattern)属于行为型模式的一种,将请求沿着一条链传递,直到该链上的某个对象处理它为止。
定义如下:一个请求有多个对象来处理,这些对象形成一条链,根据条件确定具体由谁来处理,如果当前对象不能处理则传递给该链中的下一个对象,直到有对象处理它为止。责任链模式通过将请求和处理分离开来,以进行解耦。职责链模式结构的核心在于引入了一个抽象处理者。
</>复制代码
UML结构图
</>复制代码
模式结构
Handler(抽象处理者): 定义一个处理请求的接口,提供对后续处理者的引用
ConcreteHandler(具体处理者): 抽象处理者的子类,处理用户请求,可选将请求处理掉还是传给下家;在具体处理者中可以访问链中下一个对象,以便请求的转发。
案例</>复制代码
UML图如下:
1.定义AbstractHandler(抽象处理者),使子类形成一条链
</>复制代码
public abstract class AbstractHandler {
private AbstractHandler handler;
public abstract void handleRequest(String condition);
public AbstractHandler getHandler() {
return handler;
}
public void setHandler(AbstractHandler handler) {
this.handler = handler;
}
}
2.创建若干个ConcreteHandler(具体处理者)继承AbstractHandler,在当前处理者对象无法处理时,将执行权传给下一个处理者对象
</>复制代码
public class ConcreteHandlerA extends AbstractHandler {
@Override
public void handleRequest(String condition) {
if (condition.equals("A")) {
System.out.println("ConcreteHandlerA处理");
} else {
System.out.println("ConcreteHandlerA不处理,由其他的Handler处理");
super.getHandler().handleRequest(condition);
}
}
}
public class ConcreteHandlerB extends AbstractHandler {
@Override
public void handleRequest(String condition) {
if (condition.equals("B")) {
System.out.println("ConcreteHandlerB处理");
} else {
System.out.println("ConcreteHandlerB不处理,由其他的Handler处理");
super.getHandler().handleRequest(condition);
}
}
}
public class ConcreteHandlerZ extends AbstractHandler {
@Override
public void handleRequest(String condition) {
//一般是最后一个处理者
System.out.println("ConcreteHandlerZ处理");
}
}
3.创建ChainClient(测试类)
</>复制代码
public class ChainClient {
public static void main(String[] args) {
AbstractHandler handlerA = new ConcreteHandlerA();
AbstractHandler handlerB = new ConcreteHandlerB();
AbstractHandler handlerZ = new ConcreteHandlerZ();
// 如A处理不掉转交给B
handlerA.setHandler(handlerB);
handlerB.setHandler(handlerZ);
handlerA.handleRequest("Z");
}
}
4.运行效果
</>复制代码
----------------------handleRequest("A")-------------------------
ConcreteHandlerA处理
----------------------handleRequest("B")-------------------------
ConcreteHandlerA不处理,由其他的Handler处理
ConcreteHandlerB处理
----------------------handleRequest("Z")-------------------------
ConcreteHandlerA不处理,由其他的Handler处理
ConcreteHandlerB不处理,由其他的Handler处理
ConcreteHandlerZ处理
可以看出,客户端创建了三个处理者对象,并指定第一个处理者对象的下家是第二个处理者对象,第二个处理者对象的下家是第三个处理者对象。然后客户端将请求传递给第一个处理者对象。
由于本示例的传递逻辑非常简单:只要有下家,就传给下家处理;如果没有下家,就自行处理。因此,第一个处理者对象接到请求后,会将请求传递给第二个处理者对象。由于第二个处理者对象没有下家,于是自行处理请求。活动时序图如下所示。
纯与不纯纯:要么承担全部责任,要么将责任推给下家,不允许出现某一个具体处理者对象在承担了一部分或全部责任后又将责任向下传递的情况。
不纯:允许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者可以继续处理该请求,而且一个请求可以最终不被任何处理者对象所接收。
Filter源码分析我们经常使用的Filter就使用到了责任链模式,创建一个Filter除了要在应用中做相应配置外,还需要实现javax.servlet.Filter接口。
</>复制代码
@Configuration
public class MyFilter implements Filter {
private final static Logger LOGGER = LoggerFactory.getLogger(MyFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
LOGGER.info("init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
LOGGER.info("doFilter");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
LOGGER.info("destroy");
}
}
使用DEBUG模式所看到的结果如下:
</>复制代码
Filter 集
在源码ApplicationFilterChain中,定义了一个ApplicationFilterConfig的数组来存放所有的Filter,使之形成链状
</>复制代码
public final class ApplicationFilterChain implements FilterChain {
// 扩容规则
public static final int INCREMENT = 10;
// Filter集,默认大小为 0 个
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
}
</>复制代码
ApplicationFilterConfig 装载规则
在应用首次启动时,会自动实例化对象,并从web应用中读取配置的Filter的信息,然后装进该容器。
</>复制代码
public final class ApplicationFilterConfig implements FilterConfig, Serializable {
// 省略代码...
}
</>复制代码
ApplicationFilterConfig 扩容规则
</>复制代码
//将过滤器添加到在此链条中执行的过滤器集合中。
void addFilter(ApplicationFilterConfig filterConfig) {
// 防止多次添加相同的过滤器
for(ApplicationFilterConfig filter:filters)
if(filter==filterConfig)
return;
if (n == filters.length) {
// 定义一个在原基础之上 +10 的新数组
ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT];
// 将源数组的元素拷贝到目标数组中去
System.arraycopy(filters, 0, newFilters, 0, n);
// 重新赋值
filters = newFilters;
}
//将变量filterConfig放入ApplicationFilterConfig数组中,并将当前过滤器链里面拥有的过滤器数目+1
filters[n++] = filterConfig;
}
</>复制代码
addFilter 的使用
</>复制代码
public static ApplicationFilterChain createFilterChain(ServletRequest request,Wrapper wrapper, Servlet servlet) {
//如果没有 servlet 要执行,则返回null
if (servlet == null)
return null;
// 创建和初始化过滤器链对象
ApplicationFilterChain filterChain = null;
if (request instanceof Request) {
Request req = (Request) request;
if (Globals.IS_SECURITY_ENABLED) {
// 为了安全起见:不要回收
filterChain = new ApplicationFilterChain();
} else {
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} else {
// 调度程序在使用中
filterChain = new ApplicationFilterChain();
}
filterChain.setServlet(servlet);
filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());
// 获取过滤器上下文映射
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();
// 如果没有过滤器映射,就认为当前执行完成
if ((filterMaps == null) || (filterMaps.length == 0))
return (filterChain);
// 获取匹配的过滤器映射信息
DispatcherType dispatcher =
(DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);
String requestPath = null;
Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
if (attribute != null){
requestPath = attribute.toString();
}
String servletName = wrapper.getName();
// 将相关路径映射的过滤器添加到此过滤器链中
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
if (!matchFiltersURL(filterMaps[i], requestPath))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
// 添加与servlet名称匹配的筛选器
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continue;
}
if (!matchFiltersServlet(filterMaps[i], servletName))
continue;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME - log configuration problem
continue;
}
filterChain.addFilter(filterConfig);
}
// 返回完整的过滤器链
return filterChain;
}
</>复制代码
createFilterChain 的调用
</>复制代码
final class StandardWrapperValve extends ValveBase {
public final void invoke(Request request, Response response) throws IOException, ServletException {
// 省略代码...
// 为这个请求创建过滤器链
ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();
ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper, servlet);
// 省略代码...
filterChain.doFilter(request.getRequest(), response.getResponse());
}
}
</>复制代码
执行流程
在StandardWrapperValue类的invoke()方法中调用ApplicationFilterChai类的createFilterChain()方法
在ApplicationFilterChai类的createFilterChain()方法中调用ApplicationFilterChain类的addFilter()方法
在ApplicationFilterChain类的addFilter()方法中给ApplicationFilterConfig数组赋值。
</>复制代码
最后一步
在doFilter()方法中最后会调用一个internalDoFilter()方法,目的就是执行ApplicationFilterChain中的全部过滤器,从代码中可以发现它调用了doFilter,而在doFilter又会调用internalDoFilter 从而使所有的Filter都得以调用
</>复制代码
private void internalDoFilter(ServletRequest request,ServletResponse response) throws IOException, ServletException {
// 如果存在下一个,继续调用下一个过滤器
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
} else {
// 此处调用Filter的doFilter()方法 / 而 doFilter 又会调用 internalDoFilter 直到调用完所有的过滤器
filter.doFilter(request, response, this);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}
// 从最后一个开始调用
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}
if (request.isAsyncSupported() && !servletSupportsAsync) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
// 包装请求
if ((request instanceof HttpServletRequest) &&
(response instanceof HttpServletResponse) &&
Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args,
principal);
} else {
servlet.service(request, response);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.servlet"), e);
} finally {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(null);
lastServicedResponse.set(null);
}
}
}
总结
职责链模式通过建立一条链来组织请求的处理者,请求将沿着链进行传递,请求发送者无须知道请求在何时、何处以及如何被处理,实现了请求发送者与处理者的解耦。在软件开发中,如果遇到有多个对象可以处理同一请求时可以应用职责链模式,例如在Web应用开发中创建一个过滤器(Filter)链来对请求数据进行过滤,在工作流系统中实现公文的分级审批等等,使用职责链模式可以较好地解决此类问题。
</>复制代码
优点
降低耦合度,分离了请求与处理,无须知道是哪个对象处理其请求
简化对象的相互连接,仅保持一个指向后者的引用,而不需保持所有候选接受者的引用
扩展容易,新增具体请求处理者,只需要在客户端重新建链即可,无需破坏原代码
</>复制代码
缺点
如果请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理;一个请求也可能因职责链没有被正确配置而得不到处理
较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到一定影响,而且在进行代码调试时不太方便。
如果建链不当,可能会造成循环调用,将导致系统陷入死循环。
金无足赤,人无完人。就像所有的设计模式一样,有优点优缺点,但是总的来说优点必定大于缺点或者说缺点相对于优点来说更可控。
说点什么参考文献:http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html
全文代码:https://gitee.com/battcn/design-pattern/tree/master/Chapter11/battcn-chain-responsibility
个人QQ:1837307557
battcn开源群(适合新手):391619659
微信公众号:battcn(欢迎调戏)
福利关注公众号:battcn,回复springboot即可获得
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/70629.html
摘要:面向对象常见的设计模式有策略模式模板方法观察者模式责任链模式以及工厂模式,使用表达式函数式编程思维有助于避免面向对象开发中的那些固定代码。 本文是一篇《Java 8实战》的阅读笔记,阅读大约需要5分钟。 有点标题党,但是这确实是我最近使用Lambda表达式的感受。设计模式是过去的一些好的经验和套路的总结,但是好的语言特性可以让开发者不去考虑这些设计模式。面向对象常见的设计模式有策略模式...
摘要:前言近期在做的拦截器功能,正好用到了责任链模式。通过官方图就可以非常清楚的看出是一个责任链模式用责任链模式设计一个拦截器对于拦截器来说使用责任链模式再好不过了。设置拦截器到责任链中时通过反射将的值保存到各个拦截器中。 showImg(https://segmentfault.com/img/remote/1460000016756077?w=1733&h=1300); 前言 近期在做 ...
摘要:推文用设计模式解构三国是一种什么体验行为型设计模式一策略模式工厂模式优化结构状态模式随着状态改变而改变行为。推文状态机与状态模式责任链模式多个对象依次处理请求前者指定后者。代理模式代理针对一个对象,为了增加控制等中介双方都是多个,为了解耦。 策略模式 选择使用封装好的一系列算法,可相互替换。 类比:商店[Context]买完衣服买单[Stratege](现金[Concrete Stra...
摘要:迭代器模式属于行为型模式的一种,提供一种方法访问一个容器中各个元素,而又不需要暴露该对象的内部细节。迭代器模式把在元素之间游走的责任交给迭代器,而不是聚合对象。 迭代器模式(Iterator Pattern)属于行为型模式的一种,提供一种方法访问一个容器中各个元素,而又不需要暴露该对象的内部细节。 概述 迭代器模式听起来可能感觉很陌生,但是实际上,迭代器模式是所有设计模式中最简单也是...
阅读 3036·2023-04-26 01:52
阅读 3629·2021-09-04 16:40
阅读 3719·2021-08-31 09:41
阅读 1874·2021-08-09 13:41
阅读 632·2019-08-30 15:54
阅读 3030·2019-08-30 11:22
阅读 1694·2019-08-30 10:52
阅读 1019·2019-08-29 13:24