免费网站入口网站免费进ps软件,lnmp一键包wordpress,微网站建设86215,杭州建设厅特种作业证文章目录 1、责任链模式2、spring中的责任链模式Spring InterceptorServlet FilterNetty 1、责任链模式
责任链模式为请求创建了一个接收者对象的链#xff0c;在这种模式下#xff0c;通常每个节点都包含对另一个节点者的引用。每个节点针对请求#xff0c;处理自己感兴趣… 文章目录 1、责任链模式2、spring中的责任链模式Spring InterceptorServlet FilterNetty 1、责任链模式
责任链模式为请求创建了一个接收者对象的链在这种模式下通常每个节点都包含对另一个节点者的引用。每个节点针对请求处理自己感兴趣的内容处理完之后可以结束也可以向下一个节点传递继续处理
角色
抽象处理者角色处理请求的抽象类定义了处理请求的抽象方法(抽象类或接口实现)具体处理者角色处理请求的具体实现类(持有下家对象的引用)
例请假流程都是先由本部门审核根据时间长短再进行下一级审批 //抽象类
public abstract class Handler {/*** 请假天数*/public int maxday;/*** 请假人*/public String name;public Handler(String name, int maxday) {this.maxday maxday;this.name name;}private Handler nextHandler;public void setNextHandler(Handler nextHandler) {this.nextHandler nextHandler;}/*** 处理请假判断请假天数超过本部门限定时间则交由上一级部门*/public final void handlingFakeSlips(int day) {if (this.maxday day) {this.agree(day);}else {if (nextHandler ! null) {System.out.println(name:天数已超过我的审批权限已提交我的上级审批);nextHandler.handlingFakeSlips(day);}else {System.out.println(天数时间过长准备辞职吧);}}}/*** 审批动作子类来实现* param day*/abstract void agree(int day);
}//部门实现类
public class RDDepartment extends Handler{public RDDepartment(String name, int maxday) {super(name, maxday);}Overridevoid agree(int maxday) {System.out.println(name 研发部门请假审批通过请假天数 maxday);}
}//主管实现类
public class Supervisor extends Handler{public Supervisor(String name, int maxday) {super(name, maxday);}Overridevoid agree(int maxday) {System.out.println(name 主管请假审批通过请假天数 maxday);}
}//董事实现类
public class Director extends Handler{public Director(String name, int maxday) {super(name, maxday);}Overridevoid agree(int maxday) {System.out.println(name 请假董事审批通过请假天数 maxday);}
}//组装链
public class HandlerChain {private Handler head;private Handler tail;public HandlerContext(){RDDepartment rdDepartment new RDDepartment(研发部门,5);Supervisor supervisor new Supervisor(项目主管,30);Director director new Director(董事,180);rdDepartment.setNextHandler(supervisor);supervisor.setNextHandler(director);head rdDepartment;tail director;}public void doHandler(Integer days){head.handlingFakeSlips(days);}
}//请求
public class Request {public static void main(String[] args) {HandlerChain handlerChain new HandlerChain();handlerChain.doHandler(360);}
}优点when,why 1.发送者与接收者之间的耦合度降低解耦 2.可以灵活添加新的责任链中的对象 缺点 1.不能保证请求一定被接收 2.一定程度上影响性能 这种形式很难进行动态新增和调整处理节点一种比较复杂的控制节点的形式如Netty中的责任链模式应用见下一节 2、spring中的责任链模式
Spring Interceptor
回顾springmvc处理请求的流程DispatcherServlet接收到请求后执行doDispatcher()方法流程回顾请求处理流程图
其中通过HandlerMapping获得的是HandlerExecutionChain 对象
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {//......HandlerExecutionChain mappedHandler null;//......mappedHandler getHandler(processedRequest);//...... HandlerAdapter ha getHandlerAdapter(mappedHandler.getHandler());//......
}protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings ! null) {for (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler mapping.getHandler(request);if (handler ! null) {return handler;}}}return null;
}protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters ! null) {for (HandlerAdapter adapter : this.handlerAdapters) {if (adapter.supports(handler)) {return adapter;}}}throw new ServletException(No adapter for handler [ handler ]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler);
}HandlerExecutionChain 中包含一个handler对象后面匹配能处理handler的适配器对象执行详情对应适配器模式中讲解还有一个拦截器列表ListHandlerInterceptor interceptorList所有的实现了HandlerInterceptor接口的类都会被加载进这个集合中在请求处理前后分别以责任链的形式调用拦截器的preHandle和postHandle
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {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 applyPostHandle(HttpServletRequest request, HttpServletResponse response, Nullable ModelAndView mv)throws Exception {HandlerInterceptor[] interceptors getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for (int i interceptors.length - 1; i 0; i--) {HandlerInterceptor interceptor interceptors[i];interceptor.postHandle(request, response, this.handler, mv);}}
}这里的链是由集合List维护使用List有序的特性一次调用每个拦截器通过方法返回的结果判断是否需要传递到下一个拦截器 Servlet Filter
servlet中Filter的调用也是通过责任链模式通过FilterChain作为链条的管理者
//FilterChain接口
public interface FilterChain {public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;
}//FilterChain实现类
public class MockFilterChain implements FilterChain {//......private final ListFilter filters;//......Overridepublic void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {Assert.notNull(request, Request must not be null);Assert.notNull(response, Response must not be null);Assert.state(this.request null, This FilterChain has already been called!);if (this.iterator null) {this.iterator this.filters.iterator();}if (this.iterator.hasNext()) {Filter nextFilter this.iterator.next();nextFilter.doFilter(request, response, this);}this.request request;this.response response;}
}由上可知FilterChain中管理的 ListFilter filters即为所有实现了Filter的过滤器调用过滤器的时候通过FilterChain进行链条的调用。 //Filter接口
public interface Filter {default public void init(FilterConfig filterConfig) throws ServletException {}public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)throws IOException, ServletException;default public void destroy() {}
}//Filter实现类
public class AuthFilter extends AuthenticationFilter {//......public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest httpRequest toLowerCase((HttpServletRequest)request);String tokenString httpRequest.getParameter(delegation);if (tokenString ! null) {filterChain.doFilter(httpRequest, response);} else {super.doFilter(httpRequest, response, filterChain);}}//......
}Filter的doFilter方法最后调用filterChain.doFilter(httpRequest, response);即传递至下一个Filter进行处理 Netty
Netty中的handler使用了责任链模式但是其中回调过多责任链模式的体现不清晰参考该文章**Spring中如何使用责任链模式**将责任链抽离出来完成在spring中的调用 该模型中具有多条链每条链属于不同层级链中节点为HandlerContextHandlerContext包含相邻接点的引用还有Handler的引用 Pipeline为链条的管理者通过Pipeline来调用责任链 HandlerContext为链条中节点的上下文它里面有链条的前一个节点和后一个节点的HandlerContext引用 Handler: 具体的处理程序与HandlerContext一一对应 我们先仅看Filter事件这一条链整个结构由Pipeline管理整条链 //Pipelie接口
public interface Pipeline {Pipeline fireTaskFiltered();
}//Pipeline实现类
Component(pipeline)
Scope(prototype)
public class DefaultPipeline implements Pipeline, ApplicationContextAware, InitializingBean {// 创建一个默认的handler将其注入到首尾两个节点的HandlerContext中其作用只是将链往下传递private static final Handler DEFAULT_HANDLER new Handler() {};// 将ApplicationContext注入进来的主要原因在于HandlerContext是prototype类型的因而需要// 通过ApplicationContext.getBean()方法来获取其实例private ApplicationContext context;// 创建一个头结点和尾节点这两个节点内部没有做任何处理只是默认的将每一层级的链往下传递// 这里头结点和尾节点的主要作用就是用于标志整个链的首尾所有的业务节点都在这两个节点中间private HandlerContext head;private HandlerContext tail;// 用于业务调用的request对象其内部封装了业务数据private Request request;// 用于执行任务的task对象private Task task;// 最初始的业务数据需要通过构造函数传入因为这是驱动整个pipeline所需要的数据// 一般通过外部调用方的参数进行封装即可public DefaultPipeline(Request request) {this.request request;}// 这里我们可以看到每一层级的调用都是通过HandlerContext.invokeXXX(head)的方式进行的// 也就是说我们每一层级链的入口都是从头结点开始的当然在某些情况下我们也需要从尾节点开始链// 的调用这个时候传入tail即可。// 触发任务过滤的链调用Overridepublic Pipeline fireTaskFiltered() {HandlerContext.invokeTaskFiltered(head, task);return this;}// 用于往Pipeline中添加节点的方法读者朋友也可以实现其他的方法用于进行链的维护void addLast(Handler handler) {HandlerContext handlerContext newContext(handler);tail.prev.next handlerContext;handlerContext.prev tail.prev;handlerContext.next tail;tail.prev handlerContext;}// 这里通过实现InitializingBean接口来达到初始化Pipeline的目的可以看到这里初始的时候// 我们通过ApplicationContext实例化了两个HandlerContext对象然后将head.next指向tail节点// 将tail.prev指向head节点。也就是说初始时整个链只有头结点和尾节点。Overridepublic void afterPropertiesSet() throws Exception {head newContext(DEFAULT_HANDLER);tail newContext(DEFAULT_HANDLER);head.next tail;tail.prev head;}// 使用默认的Handler初始化一个HandlerContextprivate HandlerContext newContext(Handler handler) {HandlerContext context this.context.getBean(HandlerContext.class);context.handler handler;return context;}// 注入ApplicationContext对象Overridepublic void setApplicationContext(ApplicationContext applicationContext) {this.context applicationContext;}
}Pipeline的实现类内部除了实现接口的方法其他方法均为初始化 DEFAULT_HANDLER: Pipeline管理一条链表该链表的每个节点包含HandlerContext和Handler两个对象 而链表的首和尾两个节点由Pipeline自己指定其他自定义的节点放在首尾两节点之间DEFAULT_HANDLER用来作为首尾节点的Handler不起任何作用context: 由于这些类的作用域均不是单例所以要使用ApplicationContext.getBean()方法获取所以类实现了ApplicationContextAware接口的setApplicationContext方法用于注入ApplicationContext对象private HandlerContext head, tail: 为一条链的首尾两个节点从这儿也可以看出链条的每个节点都是通过HandlerContext来引用的HandlerContext再引用一个Handler Component
Scope(prototype)
public class HandlerContext {HandlerContext prev;HandlerContext next;Handler handler;private Task task;public void fireTaskFiltered(Task task) {invokeTaskFiltered(next(), task);}/*** 处理任务过滤事件*/static void invokeTaskFiltered(HandlerContext ctx, Task task) {if (null ! ctx) {try {ctx.handler().filterTask(ctx, task);} catch (Throwable e) {ctx.handler().exceptionCaught(ctx, e);}}}private HandlerContext next() {return next;}private Handler handler() {return handler;}
}HandlerContext作为节点应有前后两个节点的引用pre next还有具体处理任务的Handler fireTaskFiltered方法供Hanndler调用将请求传递给下一个节点处理(方法实现中区下一个HandlerContext去执行) invokeTaskFiltered静态方法供Pipeline 和 上一个节点的fireTaskFiltered方法调用去执行Handler的方法 public interface Handler {/*** 查询到task之后进行task过滤的逻辑*/default void filterTask(HandlerContext ctx, Task task) {ctx.fireTaskFiltered(task);}
}Handler定义了感兴趣的事件暂时只看过滤事件 Handler的实现类由我们根据自己的需要去编写实现Handler接口即可 Component
public class DurationHandler implements Handler {Overridepublic void filterTask(HandlerContext ctx, Task task) {System.out.println(时效性检验);ctx.fireTaskFiltered(task);}
}Component
public class RiskHandler implements Handler {Overridepublic void filterTask(HandlerContext ctx, Task task) {System.out.println(风控拦截);ctx.fireTaskFiltered(task);}
}Component
public class TimesHandler implements Handler {Overridepublic void filterTask(HandlerContext ctx, Task task) {System.out.println(次数限制检验);ctx.fireTaskFiltered(task);}
}这里我们已经实现了PipelineHandlerContext和Handler知道这些bean都是被Spring所管理的bean那么我们接下来的问题主要在于如何进行整个链的组装。这里的组装方式比较简单其主要需要解决两个问题 对于后续写业务代码的人而言其只需要实现一个Handler接口即可而无需处理与链相关的所有逻辑因而我们需要获取到所有实现了Handler接口的bean将实现了Handler接口的bean通过HandlerContext进行封装然后将其添加到Pipeline中。 以上可以由spring完成通过生命实现接口BeanPostProcessor的类实现postProcessAfterInitialization方法可以在初始化完Pipeline后获取所有实现了Handler的bean并添加到pipeline中spring自动调用该方法
Component
public class HandlerBeanProcessor implements BeanPostProcessor, ApplicationContextAware {private ApplicationContext context;// 该方法会在一个bean初始化完成后调用这里主要是在Pipeline初始化完成之后获取所有实现了// Handler接口的bean然后通过调用Pipeline.addLast()方法将其添加到pipeline中Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {if (bean instanceof DefaultPipeline) {DefaultPipeline pipeline (DefaultPipeline) bean;MapString, Handler handlerMap context.getBeansOfType(Handler.class);handlerMap.forEach((name, handler) - pipeline.addLast(handler));}return bean;}Overridepublic void setApplicationContext(ApplicationContext applicationContext) {this.context applicationContext;}
}postProcessAfterInitialization(Object bean, String beanName): 实现了BeanPostProcessor的该方法在spring启动之后没初始化完成一个Bean之后都会调用该方法 如此当初始化完pipeline之后获取实现了Handler接口的所有实现类在addLast()方法中为每一个Handler初始化一个HandlerContext并添加到Pipeline中 如此下来整个过程调用如下
Service
public class ApplicationService {Autowiredprivate ApplicationContext context;public void mockedClient(Request request) {Pipeline pipeline newPipeline(request);pipeline.fireTaskFiltered();}private Pipeline newPipeline(Request request) {return context.getBean(DefaultPipeline.class, request);}
}1、spring项目启动加载和初始化Bean当加载到DefaultPipeline的时候由于实现了InitializingBean接口所以会调用初始化方法afterPropertiesSet()为DefaultPipeline添加两个首尾节点HandlerContext 2、当初始化完成Pipeline之后调用postProcessAfterInitialization(Object bean, String beanName); 3、加载所有实现了Hnadler接口的Bean并通过pipeline.addLast(Handler handler方法为每一个handler创建一个HandlerContext并添加到链条中; 至此形成了一条链 4、service想执行该链的时候通过有参构造方法将请求request传递给pipeline调用pipeline.fireTaskFiltered(); 5、pipeline.fireTaskFiltered()中会调用HandlerContext的静态方法HandlerContext.invokeTaskFiltered(HandlerContext ctx, Task task)将第一个HandlerContext传入去执行其handler的filterTask(HandlerContext ctx, Task task)方法执行具体逻辑 6、handler的filterTask(HandlerContext ctx, Task task)方法最后会调用ctx的invokeTaskFiltered(HandlerContext ctx, Task task)方法该方法会使用invokeTaskFiltered(next(), task)去执行下一个节点ctx.handler().filterTask(ctx, task) 7、直至最后到节点tail没有下一个节点会停止执行 至此单条链的责任链模式已完成 在netty中并不是一条链每一个handler有很多针对不同的事件的处理 在pipeline中有所有的事件我们相对某一个事件处理是实现handler的对应方法的处理逻辑就会在对应层级的链中加入该handlernetty多层级代码责任链参考Spring中如何使用责任链模式