顾名思义,责任链模式(Chain of Responsibility Pattern)为请求建立了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,一般每一个接收者都包含对另外一个接收者的引用。若是一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。html
意图 避免请求发送者与接收者耦合在一块儿,让多个对象都有可能接收请求,将这些对象链接成一条链,而且沿着这条链传递请求,直到有对象处理它为止。java
主要解决 职责链上的处理者负责处理请求,客户只须要将请求发送到职责链上便可,无须关心请求的处理细节和请求的传递,因此职责链将请求的发送者和请求的处理者解耦了。git
什么时候使用 在处理消息的时候以过滤不少道。github
如何解决 拦截的类都实现统一接口。web
关键代码 Handler 里面聚合它本身,在 handleRequest 里判断是否合适,若是没达到条件则向下传递。segmentfault
纯责任链与不纯责任链设计模式
主要角色安全
Handler(抽象处理者): 定义一个处理请求的接口,提供对后续处理者的引用app
ConcreteHandler(具体处理者): 抽象处理者的子类,处理用户请求,可选将请求处理掉仍是传给下家;在具体处理者中能够访问链中下一个对象,以便请求的转发jsp
应用实例
一、红楼梦中的"击鼓传花"。
二、JS 中的事件冒泡。
三、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。
优势
一、下降耦合度。它将请求的发送者和接收者解耦。
二、简化了对象。使得对象不须要知道链的结构。
三、加强给对象指派职责的灵活性。经过改变链内的成员或者调动它们的次序,容许动态地新增或者删除责任。
四、增长新的请求处理类很方便。
缺点
一、不能保证请求必定被接收。
二、系统性能将受到必定影响,并且在进行代码调试时不太方便,可能会形成循环调用。
三、可能不容易观察运行时的特征,有碍于除错。
使用场景
一、有多个对象能够处理同一个请求,具体哪一个对象处理该请求由运行时刻自动肯定。
二、在不明确指定接收者的状况下,向多个对象中的一个提交一个请求。
三、可动态指定一组对象处理请求。
travel包里主要对出行方式的责任链模式。跟进用户身上的钱,在优先级如飞机->火车->大巴的顺序下选择对应的出行模式。
public class Application {
public static void main(String[] args) {
Handler planeHandler = new PlaneHandler();
Handler trainHandler = new TrainHandler();
Handler busHandler = new BusHandler();
planeHandler.setNext(trainHandler);
trainHandler.setNext(busHandler);
planeHandler.handleRequest("老王", 40d);
planeHandler.handleRequest("张三", 140d);
planeHandler.handleRequest("李四", 240d);
planeHandler.handleRequest("吴老五", 340d);
}
}
复制代码
抽象处理
@Data
public abstract class Handler {
/** * 下一个链节点 */
protected Handler next;
public abstract void handleRequest(String name, Double wallet);
}
复制代码
具体的处理者(飞机、火车、大巴)
@Slf4j
public class PlaneHandler extends Handler {
private double price = 280d;
@Override
public void handleRequest(String name, Double wallet) {
if (price <= wallet) {
log.info("{}身上的钱能够坐飞机。", name);
return;
}
if (Objects.nonNull(next)) {
next.handleRequest(name, wallet);
return;
}
log.info("{}钱不够,只能徒步啦", name);
}
}
复制代码
@Slf4j
public class TrainHandler extends Handler {
private double price = 149.99d;
@Override
public void handleRequest(String name, Double wallet) {
if (price <= wallet) {
log.info("{}身上的钱只能坐火车。", name);
return;
}
if (Objects.nonNull(next)) {
next.handleRequest(name, wallet);
return;
}
log.info("{}钱不够,只能徒步啦", name);
}
}
复制代码
@Slf4j
public class BusHandler extends Handler {
private double price = 59.99d;
@Override
public void handleRequest(String name, Double wallet) {
if (price <= wallet) {
log.info("{}身上的钱只能坐大巴。", name);
return;
}
if (Objects.nonNull(next)) {
next.handleRequest(name, wallet);
return;
}
log.info("{}钱不够,只能徒步啦", name);
}
}
复制代码
travel2包是对travel包的从新写法。
public class Application {
public static void main(String[] args) {
HandlerChain chain = new HandlerChain();
Handler planeHandler = new PlaneHandler();
Handler trainHandler = new TrainHandler();
Handler busHandler = new BusHandler();
chain.addHandler(planeHandler);
chain.addHandler(trainHandler);
chain.addHandler(busHandler);
chain.handle("老王", 40d);
chain.handle("张三", 140d);
chain.handle("李四", 240d);
chain.handle("吴老五", 340d);
}
}
复制代码
抽象处理者
public interface Handler {
void handleRequest(String name, Double wallet, HandlerChain chain);
}
复制代码
具体处理者(飞机、火车、大巴)
@Slf4j
public class PlaneHandler implements Handler {
private double price = 280d;
@Override
public void handleRequest(String name, Double wallet, HandlerChain chain) {
if (price <= wallet) {
log.info("{}身上的钱能够坐飞机。", name);
chain.reuse();
return;
}
chain.handle(name, wallet);
}
}
复制代码
@Slf4j
public class TrainHandler implements Handler {
private double price = 149.99d;
@Override
public void handleRequest(String name, Double wallet, HandlerChain chain) {
if (price <= wallet) {
log.info("{}身上的钱只能坐火车。", name);
chain.reuse();
return;
}
chain.handle(name, wallet);
}
}
复制代码
@Slf4j
public class BusHandler implements Handler {
private double price = 59.99d;
@Override
public void handleRequest(String name, Double wallet, HandlerChain chain) {
if (price <= wallet) {
log.info("{}身上的钱只能坐大巴。", name);
chain.reuse();
return;
}
chain.handle(name, wallet);
}
}
复制代码
责任链管理者
@Slf4j
public class HandlerChain {
private List<Handler> handlerList = new ArrayList<>();
/** * 维护当前链上位置 */
private int pos;
/** * 链的长度 */
private int handlerLength;
public void addHandler(Handler handler) {
handlerList.add(handler);
handlerLength = handlerList.size();
}
public void handle(String name, double wallet) {
if (CollectionUtils.isEmpty(handlerList)) {
log.error("有钱,但没提供服务,{}也估计就只能步行了。", name);
return;
}
if (pos >= handlerLength) {
log.error("身上钱不够,{}也估计就只能步行了。", name);
reuse();
return;
}
Handler handler = handlerList.get(pos++);
if (Objects.isNull(handler)) {
log.error("假服务,{}也估计就只能步行了。", name);
reuse();
return;
}
handler.handleRequest(name, wallet, this);
}
/** * 链从新使用 */
public void reuse() {
pos = 0;
}
}
复制代码
待补充...
补充补充遗留的Filter过滤器中的责任链处理。
本次主要是对Tomcat中的Filter处理简单的梳理,若有不正确的地方,还望指出来,你们互勉,共进。
老项目你们能够在web.xml中配置filter,现使用Springboot后,也有两种配置filter方式,经过建立FilterRegistrationBean的方式和经过注解@WebFilter+@ServletComponentScan的方式。
三个主要的角色
FIlter,很少介绍了。
FilterChain servlet容器提供的开发调用链的过滤请求的资源。经过调用下一个filter实现过滤,在总体链上。
FilterConfig filter的配置器,在servlet容器在Filter初始化的时候传递信息。
具体的filter,主要说说Spring中的两个抽象Filter,GenericFilterBean和OncePerRequestFilter。
前者主要是作init和destroy的操做,重点仍是init方法,destroy只是空实现而已。
后者主要是作真正的doFilter操做,也是咱们在Spring中建立Filter一般继承的。
而ApplicationFilterChain就算Tomcat中的FilterChain实现。
/** * The int which is used to maintain the current position * in the filter chain. */
private int pos = 0;
/** * The int which gives the current number of filters in the chain. */
private int n = 0;
@Override
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
//安全相关的,暂不关注
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
try {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws ServletException, IOException {
internalDoFilter(req,res);
return null;
}
}
);
} catch( PrivilegedActionException pe) {
Exception e = pe.getException();
if (e instanceof ServletException)
throw (ServletException) e;
else if (e instanceof IOException)
throw (IOException) e;
else if (e instanceof RuntimeException)
throw (RuntimeException) e;
else
throw new ServletException(e.getMessage(), e);
}
} else {
//真正的doFilter
internalDoFilter(request,response);
}
}
private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
//pos 调用链中当前链接点所在的位置
//n 调用链总节点长度
// Call the next filter if there is one
if (pos < n) {
//对节点进行自增 pos++
ApplicationFilterConfig filterConfig = filters[pos++];
try {
//当前节点小于总长度后,从filter配置类中取出filter
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
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;
}
// We fell off the end of the chain -- call the servlet instance
//到了调用链结尾处,就真正调用servlet实例的servlet.service(request, response);
try {
if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
lastServicedRequest.set(request);
lastServicedResponse.set(response);
}
if (request.isAsyncSupported() && !servletSupportsAsync) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
// Use potentially wrapped request from this point
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);
}
}
}
/** * Prepare for reuse of the filters and wrapper executed by this chain. * 重复使用filter调用链,pos重设为0 */
void reuse() {
pos = 0;
}
复制代码
重点从ApplicationFilterChain中挑出几个重要的方法拿出来分析下Filter的调用链,其实还有几处没有具体讲到,ApplicationFilterChain是合适建立的,Filter是怎么加入到ApplicationFilterChain中的。这涉及到Tomcat是怎样加载Content的,下次分析Tomcat的时候,再来具体分析,它是如何运做的,如何加载web.xml。
Filter、FilterConfig、FilterChain|菜鸟教程