security是一个基于过滤器拦截器实现的框架。它内置了十几个过滤器(看的头大)。所以说过滤器在这个框架中扮演了不可或缺的角色。过滤器链的执行类似于一个净水器,你发的请求就像不干净的水,然后净水器中的每一环都会对水进行过滤,其中有过滤金属的,过滤有害物质的等等,这些过滤组件依照一定的顺序组合起来使用就能达到很好的效果。过滤器的执行逻辑就是基于:责任链模式。
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。它可以使数据的发送者和接收者解耦,数据沿着责任链传递,直到有一个对象处理了它为止。
责任链模式有两种实现方式:一种基于单链表实现,一种依靠集合实现。第一种比较好理解,第二种使用的更广泛,FilterChain也是使用这种方式。光看说明可能会有点懵,上代码。
首先我们需要一个要被处理的数据,这个数据在实际开发中有可能是请求或是其他的。

  1. public interface DataResource {
  2. void doSomething();
  3. }
  1. public class DataResourceImpl implements DataResource{
  2. //业务数据
  3. private Integer data = 0;
  4. @Override
  5. public void doSomething() {
  6. data++;
  7. }
  8. public Integer getData(){
  9. return data;
  10. }
  11. }

一、单链表方式:

当然,用单链表实现的前提需要搞懂单链表这个简单的数据结构~

  1. public abstract class AbstractHandler {
  2. private AbstractHandler next;
  3. /**
  4. * 执行逻辑
  5. */
  6. public abstract void handleRequest(DataResource dataResource);
  7. public AbstractHandler getNext(){
  8. return next;
  9. }
  10. public void setNext(AbstractHandler next){
  11. this.next = next;
  12. }
  13. }

定义一个抽象类,我定义的过滤节点都会继承它。

  1. public class Handler extends AbstractHandler{
  2. @Override
  3. public void handleRequest(DataResource dataResource) {
  4. dataResource.doSomething();
  5. }
  6. }

实现类重写处理方法。

  1. public class StrongerHandler extends AbstractHandler{
  2. @Override
  3. public void handleRequest(DataResource dataResource) {
  4. for (int i = 0; i < 5; i++) {
  5. dataResource.doSomething();
  6. }
  7. }
  8. }

再搞一个实现类,他会对被处理类的方法执行5次。

  1. public class LinkHandlerUtil {
  2. private static AbstractHandler head = new Handler();
  3. /**
  4. * 功能描述 :遍历链表添加节点
  5. * @author HKH
  6. * @date
  7. * @param
  8. * @return
  9. */
  10. public static void addHandler(AbstractHandler handler){
  11. AbstractHandler temp = head;
  12. while(true){
  13. if(temp.getNext()==null){
  14. temp.setNext(handler);
  15. break;
  16. }
  17. temp = temp.getNext();
  18. }
  19. }
  20. /**
  21. * 功能描述 :依次执行所有节点
  22. * @author HKH
  23. * @date
  24. * @param
  25. * @return
  26. */
  27. public static void HandleAll(DataResource dataResource){
  28. AbstractHandler temp ;
  29. if(head.getNext()==null){
  30. System.out.println("这是个空链表,请先添加节点。");
  31. return;
  32. }
  33. temp = head.getNext();
  34. while (true){
  35. if(temp==null){
  36. System.out.println("所有节点执行完毕,退出。");
  37. break;
  38. }
  39. temp.handleRequest(dataResource);
  40. temp = temp.getNext();
  41. }
  42. }
  43. }

由于我没有在过滤节点处实现链表式的调用,所以我这里写了一个工具类,该类包含对过滤链的添加和调用方法。

  1. public class Test {
  2. public static void main(String[] args) {
  3. AbstractHandler handler = new Handler();
  4. AbstractHandler strong = new StrongerHandler();
  5. LinkHandlerUtil.addHandler(handler);
  6. LinkHandlerUtil.addHandler(strong);
  7. DataResourceImpl dataResource = new DataResourceImpl();
  8. LinkHandlerUtil.HandleAll(dataResource);
  9. System.out.println(dataResource.getData());
  10. }
  11. }

经测试结果为 6.

二、通过处理器集合来定义处理顺序:

这种方法的好处就是可以集中维护所有节点。

  1. /**
  2. * @program: JavaSe
  3. * @description: 责任链接口,对责任链进行抽象
  4. * @author: HKH
  5. * @create: 2019-11-28 14:43
  6. **/
  7. public interface HandlerChain {
  8. /**
  9. * 功能描述 :增加责任链节点
  10. * @author HKH
  11. * @date
  12. * @param
  13. * @return
  14. */
  15. void addHandler(Handler handler);
  16. /**
  17. * 功能描述 :执行责任链
  18. * @author HKH
  19. * @date
  20. * @param
  21. * @return
  22. */
  23. void doChain(DataResource dataResource);
  24. }

对过滤器链进行抽象,其拥有增加节点和执行方法。

  1. public class ListHandlerChainImpl implements HandlerChain{
  2. //当前handler的指针
  3. private Integer index = 0;
  4. //存放handler的集合
  5. private List<Handler> handlers = new ArrayList<>();
  6. @Override
  7. public void addHandler(Handler handler) {
  8. handlers.add(handler);
  9. }
  10. @Override
  11. public void doChain(DataResource dataResource) {
  12. int size = handlers.size();
  13. if(index<size){
  14. Handler handler = handlers.get(index++);
  15. handler.doHandler(dataResource,this);
  16. }
  17. }
  18. }

ListHandlerChainImpl 负责维护调用链条的顺序,这里实现用List来管理Handler。不过请注意这个Handler跟我之前定义的Handler有所不同,继续往下看。

  1. public interface Handler{
  2. void doHandler(DataResource dataResource, HandlerChain handlerChain);
  3. }
  1. public class HandlerImpl implements Handler{
  2. @Override
  3. public void doHandler(DataResource dataResource, HandlerChain handlerChain) {
  4. //处理业务
  5. DataResourceImpl dataResourceImpl = (DataResourceImpl) dataResource;
  6. dataResourceImpl.doSomething();
  7. handlerChain.doChain(dataResource);
  8. }
  9. }

根据代码我们可以看出,该Handler可以决定是否继续向下执行,是不是和我们学过的过滤器越来越像了!而且处理完方法后会调回到HandlerChain处继续遍历下一个节点。我们来测试一下。

  1. public class Test {
  2. public static void main(String[] args) {
  3. HandlerChain handlerChain = new ListHandlerChainImpl();
  4. handlerChain.addHandler(new HandlerImpl());
  5. handlerChain.addHandler(new HandlerImpl());
  6. DataResourceImpl dataResource = new DataResourceImpl();
  7. handlerChain.doChain(dataResource);
  8. System.out.println(dataResource.getData());
  9. }
  10. }

测试结果为 2.

小总结:

优点:
  • 责任链模式降低了请求发送者和处理者的耦合度。
  • 提高系统的灵活性。

    缺点:
  • 第一种方式不灵活,每次都要从头遍历到尾。

  • 第二种方式类似于递归调用,逻辑有些复杂。