「DUBBO系列」责任链模式源码分析

系统管理员 2021-09-24 09:14 401阅读 0赞

欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我微信「java_front」一起交流学习

1 文章概述

责任链模式将请求发送和接收解耦,让多个接收对象都有机会处理这个请求。这些接收对象串成一条链路并沿着这条链路传递这个请求,直到链路上某个接收对象能够处理它。本文我们介绍责任链模式两种应用场景和四种代码实现方式,最后介绍了DUBBO如何应用责任链构建过滤器链路。

2 应用场景

2.1 命中立即中断

我们实现一个关键词过滤功能。系统设置三个关键词过滤器,输入内容命中任何一个过滤器规则就返回校验不通过,链路立即中断无需继续进行。

(1) 实现方式一

  1. public interface ContentFilter {
  2. public boolean filter(String content);
  3. }
  4. public class AaaContentFilter implements ContentFilter {
  5. private final static String KEY_CONTENT = "aaa";
  6. @Override
  7. public boolean filter(String content) {
  8. boolean isValid = Boolean.FALSE;
  9. if (StringUtils.isEmpty(content)) {
  10. return isValid;
  11. }
  12. isValid = !content.contains(KEY_CONTENT);
  13. return isValid;
  14. }
  15. }
  16. public class BbbContentFilter implements ContentFilter {
  17. private final static String KEY_CONTENT = "bbb";
  18. @Override
  19. public boolean filter(String content) {
  20. boolean isValid = Boolean.FALSE;
  21. if (StringUtils.isEmpty(content)) {
  22. return isValid;
  23. }
  24. isValid = !content.contains(KEY_CONTENT);
  25. return isValid;
  26. }
  27. }
  28. public class CccContentFilter implements ContentFilter {
  29. private final static String KEY_CONTENT = "ccc";
  30. @Override
  31. public boolean filter(String content) {
  32. boolean isValid = Boolean.FALSE;
  33. if (StringUtils.isEmpty(content)) {
  34. return isValid;
  35. }
  36. isValid = !content.contains(KEY_CONTENT);
  37. return isValid;
  38. }
  39. }

具体过滤器已经编写完成,接下来构造过滤器责任链路

  1. @Service
  2. public class FilterHandlerChain {
  3. private FilterHandler head = null;
  4. private FilterHandler tail = null;
  5. @PostConstruct
  6. public void init() {
  7. FilterHandler aaaHandler = new AaaContentFilterHandler();
  8. FilterHandler bbbHandler = new BbbContentFilterHandler();
  9. FilterHandler cccHandler = new CccContentFilterHandler();
  10. addHandler(aaaHandler);
  11. addHandler(bbbHandler);
  12. addHandler(cccHandler);
  13. }
  14. public void addHandler(FilterHandler handler) {
  15. if (head == null) {
  16. head = tail = handler;
  17. }
  18. /** 设置当前tail继任者 **/
  19. tail.setSuccessor(handler);
  20. /** 指针重新指向tail **/
  21. tail = handler;
  22. }
  23. public boolean filter(String content) {
  24. if (null == head) {
  25. throw new RuntimeException("FilterHandlerChain is empty");
  26. }
  27. /** head发起调用 **/
  28. return head.filter(content);
  29. }
  30. }
  31. public class Test {
  32. public static void main(String[] args) throws Exception {
  33. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "classpath*:META-INF/chain/spring-core.xml" });
  34. FilterHandlerChain chain = (FilterHandlerChain) context.getBean("filterHandlerChain");
  35. System.out.println(context);
  36. boolean result1 = chain.filter("ccc");
  37. boolean result2 = chain.filter("ddd");
  38. System.out.println("校验结果1=" + result1);
  39. System.out.println("校验结果2=" + result2);
  40. }
  41. }

(2) 实现方式二

  1. public abstract class FilterHandler {
  2. /** 下一个节点 **/
  3. protected FilterHandler successor = null;
  4. public void setSuccessor(FilterHandler successor) {
  5. this.successor = successor;
  6. }
  7. public final boolean filter(String content) {
  8. /** 执行自身方法 **/
  9. boolean isValid = doFilter(content);
  10. if (!isValid) {
  11. System.out.println("校验不通过");
  12. return isValid;
  13. }
  14. /** 执行下一个节点链路 **/
  15. if (successor != null && this != successor) {
  16. isValid = successor.filter(content);
  17. }
  18. return isValid;
  19. }
  20. /** 每个节点过滤方法 **/
  21. protected abstract boolean doFilter(String content);
  22. }
  23. public class AaaContentFilterHandler extends FilterHandler {
  24. private final static String KEY_CONTENT = "aaa";
  25. @Override
  26. protected boolean doFilter(String content) {
  27. boolean isValid = Boolean.FALSE;
  28. if (StringUtils.isEmpty(content)) {
  29. return isValid;
  30. }
  31. isValid = !content.contains(KEY_CONTENT);
  32. return isValid;
  33. }
  34. }
  35. // 省略其它过滤器代码

具体过滤器已经编写完成,接下来构造过滤器责任链路

  1. @Service
  2. public class FilterHandlerChain {
  3. private FilterHandler head = null;
  4. private FilterHandler tail = null;
  5. @PostConstruct
  6. public void init() {
  7. FilterHandler aaaHandler = new AaaContentFilterHandler();
  8. FilterHandler bbbHandler = new BbbContentFilterHandler();
  9. FilterHandler cccHandler = new CccContentFilterHandler();
  10. addHandler(aaaHandler);
  11. addHandler(bbbHandler);
  12. addHandler(cccHandler);
  13. }
  14. public void addHandler(FilterHandler handler) {
  15. if (head == null) {
  16. head = tail = handler;
  17. }
  18. /** 设置当前tail继任者 **/
  19. tail.setSuccessor(handler);
  20. /** 指针重新指向tail **/
  21. tail = handler;
  22. }
  23. public boolean filter(String content) {
  24. if (null == head) {
  25. throw new RuntimeException("FilterHandlerChain is empty");
  26. }
  27. /** head发起调用 **/
  28. return head.filter(content);
  29. }
  30. }
  31. public class Test {
  32. public static void main(String[] args) throws Exception {
  33. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "classpath*:META-INF/chain/spring-core.xml" });
  34. FilterHandlerChain chain = (FilterHandlerChain) context.getBean("filterHandlerChain");
  35. System.out.println(context);
  36. boolean result1 = chain.filter("ccc");
  37. boolean result2 = chain.filter("ddd");
  38. System.out.println("校验结果1=" + result1);
  39. System.out.println("校验结果2=" + result2);
  40. }
  41. }

2.2 全链路执行

我们实现一个考题生成功能。在线考试系统根据不同年级生成不同考题。系统设置三个考题生成器,每个生成器都会执行,根据学生年级决定是否生成考题,无需生成则执行下一个生成器。

(1) 实现方式一

  1. public interface QuestionGenerator {
  2. public Question generateQuestion(String gradeInfo);
  3. }
  4. public class AaaQuestionGenerator implements QuestionGenerator {
  5. @Override
  6. public Question generateQuestion(String gradeInfo) {
  7. if (!gradeInfo.equals("一年级")) {
  8. return null;
  9. }
  10. Question question = new Question();
  11. question.setId("aaa");
  12. question.setScore(10);
  13. return question;
  14. }
  15. }
  16. // 省略其它生成器代码

具体生成器已经编写完成,接下来构造生成器责任链路

  1. @Service
  2. public class QuestionChain {
  3. private List<QuestionGenerator> generators = new ArrayList<QuestionGenerator>();
  4. @PostConstruct
  5. public void init() {
  6. QuestionGenerator aaaQuestionGenerator = new AaaQuestionGenerator();
  7. QuestionGenerator bbbQuestionGenerator = new BbbQuestionGenerator();
  8. QuestionGenerator cccQuestionGenerator = new CccQuestionGenerator();
  9. generators.add(aaaQuestionGenerator);
  10. generators.add(bbbQuestionGenerator);
  11. generators.add(cccQuestionGenerator);
  12. }
  13. public List<Question> generate(String gradeInfo) {
  14. if (CollectionUtils.isEmpty(generators)) {
  15. throw new RuntimeException("QuestionChain is empty");
  16. }
  17. List<Question> questions = new ArrayList<Question>();
  18. for (QuestionGenerator generator : generators) {
  19. Question question = generator.generateQuestion(gradeInfo);
  20. if (null == question) {
  21. continue;
  22. }
  23. questions.add(question);
  24. }
  25. return questions;
  26. }
  27. }
  28. public class Test {
  29. public static void main(String[] args) {
  30. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "classpath*:META-INF/chain/spring-core.xml" });
  31. System.out.println(context);
  32. QuestionChain chain = (QuestionChain) context.getBean("questionChain");
  33. List<Question> questions = chain.generate("一年级");
  34. System.out.println(questions);
  35. }
  36. }

(2) 实现方式二

  1. public abstract class GenerateHandler {
  2. /** 下一个节点 **/
  3. protected GenerateHandler successor = null;
  4. public void setSuccessor(GenerateHandler successor) {
  5. this.successor = successor;
  6. }
  7. public final List<Question> generate(String gradeInfo) {
  8. List<Question> result = new ArrayList<Question>();
  9. /** 执行自身方法 **/
  10. Question question = doGenerate(gradeInfo);
  11. if (null != question) {
  12. result.add(question);
  13. }
  14. /** 执行下一个节点链路 **/
  15. if (successor != null && this != successor) {
  16. List<Question> successorQuestions = successor.generate(gradeInfo);
  17. if (null != successorQuestions) {
  18. result.addAll(successorQuestions);
  19. }
  20. }
  21. return result;
  22. }
  23. /** 每个节点生成方法 **/
  24. protected abstract Question doGenerate(String gradeInfo);
  25. }
  26. public class AaaGenerateHandler extends GenerateHandler {
  27. @Override
  28. protected Question doGenerate(String gradeInfo) {
  29. if (!gradeInfo.equals("一年级")) {
  30. return null;
  31. }
  32. Question question = new Question();
  33. question.setId("aaa");
  34. question.setScore(10);
  35. return question;
  36. }
  37. }
  38. // 省略其它生成器代码

具体生成器已经编写完成,接下来构造生成器责任链路

  1. @Service
  2. public class GenerateChain {
  3. private GenerateHandler head = null;
  4. private GenerateHandler tail = null;
  5. @PostConstruct
  6. public void init() {
  7. GenerateHandler aaaHandler = new AaaGenerateHandler();
  8. GenerateHandler bbbHandler = new BbbGenerateHandler();
  9. GenerateHandler cccHandler = new CccGenerateHandler();
  10. addHandler(aaaHandler);
  11. addHandler(bbbHandler);
  12. addHandler(cccHandler);
  13. }
  14. public void addHandler(GenerateHandler handler) {
  15. if (head == null) {
  16. head = tail = handler;
  17. }
  18. /** 设置当前tail继任者 **/
  19. tail.setSuccessor(handler);
  20. /** 指针重新指向tail **/
  21. tail = handler;
  22. }
  23. public List<Question> generate(String gradeInfo) {
  24. if (null == head) {
  25. throw new RuntimeException("GenerateChain is empty");
  26. }
  27. /** head发起调用 **/
  28. return head.generate(gradeInfo);
  29. }
  30. }
  31. public class Test {
  32. public static void main(String[] args) {
  33. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "classpath*:META-INF/chain/spring-core.xml" });
  34. GenerateChain chain = (GenerateChain) context.getBean("generateChain");
  35. System.out.println(context);
  36. List<Question> result = chain.generate("一年级");
  37. System.out.println(result);
  38. }
  39. }

3 DUBBO构建过滤器链

生产者和消费者最终执行对象都是过滤器链路最后一个节点,整个链路包含多个过滤器进行业务处理。我们看看生产者和消费者默认过滤器链路。

  1. # 生产者过滤器链路
  2. EchoFilter > ClassloaderFilter > GenericFilter > ContextFilter >
  3. TraceFilter > TimeoutFilter > MonitorFilter > ExceptionFilter > AbstractProxyInvoker
  4. # 消费者过滤器链路
  5. ConsumerContextFilter > FutureFilter > MonitorFilter > DubboInvoker

ProtocolFilterWrapper作为链路生成核心通过匿名类方式构建过滤器链路,我们以消费者构建过滤器链路为例

  1. public class ProtocolFilterWrapper implements Protocol {
  2. private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
  3. // invoker = DubboInvoker
  4. Invoker<T> last = invoker;
  5. // 查询符合条件过滤器列表
  6. List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
  7. if (!filters.isEmpty()) {
  8. for (int i = filters.size() - 1; i >= 0; i--) {
  9. final Filter filter = filters.get(i);
  10. final Invoker<T> next = last;
  11. // 构造一个简化Invoker
  12. last = new Invoker<T>() {
  13. @Override
  14. public Class<T> getInterface() {
  15. return invoker.getInterface();
  16. }
  17. @Override
  18. public URL getUrl() {
  19. return invoker.getUrl();
  20. }
  21. @Override
  22. public boolean isAvailable() {
  23. return invoker.isAvailable();
  24. }
  25. @Override
  26. public Result invoke(Invocation invocation) throws RpcException {
  27. // 构造过滤器链路
  28. Result result = filter.invoke(next, invocation);
  29. if (result instanceof AsyncRpcResult) {
  30. AsyncRpcResult asyncResult = (AsyncRpcResult) result;
  31. asyncResult.thenApplyWithContext(r -> filter.onResponse(r, invoker, invocation));
  32. return asyncResult;
  33. } else {
  34. return filter.onResponse(result, invoker, invocation);
  35. }
  36. }
  37. @Override
  38. public void destroy() {
  39. invoker.destroy();
  40. }
  41. @Override
  42. public String toString() {
  43. return invoker.toString();
  44. }
  45. };
  46. }
  47. }
  48. return last;
  49. }
  50. @Override
  51. public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
  52. // RegistryProtocol不构造过滤器链路
  53. if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
  54. return protocol.refer(type, url);
  55. }
  56. Invoker<T> invoker = protocol.refer(type, url);
  57. return buildInvokerChain(invoker, Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER);
  58. }
  59. }

4 文章总结

面向对象设计有一个重要原则:对扩展开放对修改关闭,我认为这是最重要的面向对象设计原则,责任链模式非常好得体现了这个原则,有助于代码维护和处理复杂场景。

本文我们分析了责任链模式两种场景和四种代码实现方式,最后介绍了DUBBO如何应用责任链构建过滤器链路。后续文章继续分析DUBBO设计模式实例请继续关注。

欢迎大家关注公众号「JAVA前线」查看更多精彩分享文章,主要包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时欢迎大家加我微信「java_front」一起交流学习

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dvc2hpeHV5ZQ_size_16_color_FFFFFF_t_70

发表评论

表情:
评论列表 (有 0 条评论,401人围观)

还没有评论,来说两句吧...

相关阅读

    相关 责任模式

    > 责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求

    相关 责任模式

    在公众号的前面我们说策略模式的时候,我们说各种策略的对象和一个行为随着策略对象改变而改变的。换句话说,针对客户端传来不同的参数进行实例不同策略的对象,也就是说保证了客户端和服务