当前位置: 首页 > news >正文

组件开发系列--Apache Commons Chain

一、前言

        Commons-chain是apache commons中的一个子项目,主要被使用在"责任链"的场景中,struts中action的调用过程,就是使用了"chain"框架做支撑.如果你的项目中,也有基于此种场景的需求,可以考虑使用它.

        在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。即,在流水线上,属于自己的就处理,不属于自己的就丢给下一个处理。
(具体可以查看菜鸟教程:责任链模式 | 菜鸟教程)

二、 Commons Chain 

一、关系图

二、接口详解 

一、Command 接口

 Chain 中的具体某一步要执行的命令。它只有一个方法:

boolean execute(Context context) 

如果返回 true ,那么表示 Chain 的处理结束,

如果返回 false ,那么表示Chain 中的其他命令不会被调用(也就是不执行这个command);然后Chain 会继续调用下一个 Command 。

从开始执行到结束会出现三种情况:

1、 Command 返回 true;

2、Command 抛出异常;

3、一直执行到 Chain 的末尾;

注意:context对象表示当前"责任链"的上下文信息,它可以用来保存一些临时变量(可以在command间共享)

二、 Chain 接口 

它表示“命令链”,要在其中执行的命令,需要先添加到 Chain 中。 Chain 的父接口是 Command , ChainBase 实现了它。它有两个方法:

// 可以添加多个command

void addCommand(Command var1);

// ChainBase 执行责任链的时候会调用这个方法,然后这个方法会调用每个command的execute方法去执行。

boolean execute(Context var1) throws Exception;

由于直接继承自Command接口,所以Chain也是一种Command。Command 类和Chain类的关系就是组合模式,Chain不仅由多个Command组成,而且自己也是Command。

三、 Context 接口 

它表示命令执行的上下文,在命令间实现共享信息的传递。 Context 接口的父接口是 Map , ContextBase 实现了 Context 。

 另外观察 ContextBase的构造函数实现,可以发现ContextBase在初始化的时候会对本身使用反射进行处理,提取自身的自定义属性,并以键值对的形式推入到自身容器中,这样可以直接通过context.get("beanPropertyName")来获取相应的值。

四、 Filter 接口 

当有命令抛出错误时链就会非正常结束。在Commons Chain中,如果有命令抛出错误,链的执行就会中断。不论是运行时错误(runtime exception)还是应用错误(application exception),都会抛出给链的调用者。但是许多应用都需要对在命令之外定义的错误做明确的处理。Commons Chain提供了Filter接口来满足这个要求。

它的父接口是 Command ,它是一种特殊的 Command 。除了 Command 的 execute ,它还包括一个方法:

boolean postprocess(Context context, Exception exception) 

 Commons Chain 会在执行了 Filter 的 execute 方法之后,执行 postprocess (不论 Chain 以何种方式结束)。

 Filter 的执行 execute 的顺序与 Filter 出现在 Chain 中出现的位置一致,但是执行 postprocess 顺序与之相反。

如:如果连续定义了 filter1 和 filter2 ,那么execute 的执行顺序是: filter1 -> filter2 ;而 postprocess 的执行顺序是: filter2 -> filter1 。postprocess 方法只会在链的最后执行。

postprocess方法将在链执行完毕或抛出错误后执行。当一个错误被抛出时, postprocess方法处理完后会返回true,表示错误处理已经完成。链的执行并不会就此结束,但是本质上来说这个错误被捕捉而且不会再向外抛出。如果postprocess方法返回false,那错误会继续向外抛出,然后链就会非正常结束。 

五、 Catalog 接口

它是逻辑命名的 Chain 和 Command 集合。通过使用它, Command 的调用者不需要了解具体实现 Command 的类名,只需要通过名字就可以获取所需要的 Command 实例。

比如:你在chain中则增加了Commond

  // 增加命令的顺序也决定了执行命令的顺序

    public CommandChain(){

        addCommand( new Command1());

        addCommand( new Command2());

        addCommand( new Command3());

    }

那你可以通过

Catalog catalog= CatalogFactoryBase.getInstance().getCatalog();

Command  cmd= catalog.getCommand( "command1");

获取到对应的command,然后单独执行这个Commmand;

  cmd.execute( context);

context:传入的是 Context对象。

三、网上常用的使用方式 

public abstract class SellVehicleTemplate {  // 销售汽车 public void sellVehicle() {  testDriveVehicle();  negotiateSale();  arrangeFinancing();  closeSale();  }  // 试车public abstract void testDriveVehicle();  // 销售谈判public abstract void negotiateSale();  // 安排财务public abstract void arrangeFinancing();  // 结束销售public abstract void closeSale();  
}  
import org.apache.commons.chain.Command;  
import org.apache.commons.chain.Context;  
// 试车(继承Command)
public class TestDriveVehicle implements Command {  public boolean execute(Context ctx) throws Exception {  System.out.println("Test drive the vehicle");  return false;  }  
}  
// 销售谈判
public class NegotiateSale implements Command {  public boolean execute(Context ctx) throws Exception {  System.out.println("Negotiate sale");  return false;  }    
}  
// 安排财务
public class ArrangeFinancing implements Command {  public boolean execute(Context ctx) throws Exception {  System.out.println("Arrange financing");  return false;  }    
}  
// 结束销售
public class CloseSale implements Command {  public boolean execute(Context ctx) throws Exception {  System.out.println("Congratulations " + ctx.get("customerName") +", you bought a new car!");  return false;  }  
}  // 定义责任链并测试
import org.apache.commons.chain.impl.ChainBase;  
import org.apache.commons.chain.Command;  
import org.apache.commons.chain.Context;  
import org.apache.commons.chain.impl.ContextBase;  
// 继承ChainBase
public class SellVehicleChain extends ChainBase {  public SellVehicleChain() {  super();  addCommand(new GetCustomerInfo());  addCommand(new TestDriveVehicle());  addCommand(new NegotiateSale());  addCommand(new ArrangeFinancing());  addCommand(new CloseSale());  }  public static void main(String[] args) throws Exception {  Command process = new SellVehicleChain();  Context ctx = new ContextBase();  process.execute(ctx);  }  // 运行结果:
Test drive the vehicle 
Negotiate sale 
Arrange financing 
Congratulations George Burdell, you bought a new car! 

 Commons Chain提供了配置文件的方式定义责任链,在项目资源目录中创建chain- config.xml文件

<catalog>  <chain name="sell-vehicle">  <command id="GetCustomerInfo" className="com.jadecove.chain.sample.GetCustomerInfo"/>  <command id="TestDriveVehicle" className="com.jadecove.chain.sample.TestDriveVehicle"/>  <command id="NegotiateSale" className="com.jadecove.chain.sample.NegotiateSale"/>  <command id="ArrangeFinancing" className="com.jadecove.chain.sample.ArrangeFinancing"/>  <command id="CloseSale" className="com.jadecove.chain.sample.CloseSale"/>  </chain>  
</catalog>// 从xml配置中读取
public class CatalogLoader {  private static final String CONFIG_FILE = "/com/jadecove/chain/sample/chain-config.xml";  private ConfigParser parser;  private Catalog catalog;  public CatalogLoader() {  parser = new ConfigParser();  }  public Catalog getCatalog() throws Exception {  if (catalog == null) {  parser.parse(this.getClass().getResource(CONFIG_FILE));  }  catalog = CatalogFactoryBase.getInstance().getCatalog();  return catalog;  }  public static void main(String[] args) throws Exception {  CatalogLoader loader = new CatalogLoader();  Catalog sampleCatalog = loader.getCatalog();  Command command = sampleCatalog.getCommand("sell-vehicle");  Context ctx = new SellVehicleContext();  command.execute(ctx);  }  
}  

相关文章:

组件开发系列--Apache Commons Chain

一、前言 Commons-chain是apache commons中的一个子项目,主要被使用在"责任链"的场景中,struts中action的调用过程,就是使用了"chain"框架做支撑.如果你的项目中,也有基于此种场景的需求,可以考虑使用它. 在责任链模式里&#xff0c;很多对象由每一个对象对…...

60 # http 的基本概念

什么是 HTTP&#xff1f; 通常的网络是在 TCP/IP 协议族的基础上来运作的&#xff0c;HTTP 是一个子集。http 基于 tcp 的协议&#xff0c;在 tcp 的基础上增加了一些规范&#xff0c;就是 header&#xff0c;学习 http 就是学习每个 header 它有什么作用。 TCP/IP 协议族 协…...

云计算迎来中场战役,MaaS或将成为弯道超车“新赛点”

科技云报道原创。 没有人能预见未来&#xff0c;但我们可以因循常识&#xff0c;去捕捉技术创新演进的节奏韵脚。 2023年最火的风口莫过于大模型。 2022年底&#xff0c;由美国初创企业OpenAI开发的聊天应用ChatGPT引爆市场&#xff0c;生成式AI成为科技市场热点&#xff0c…...

最新基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法

文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量化的综合性知识体系。特别是&#xff0c;信息可视化技术手段和方法的运用&#xff0c;可直观的展示主题的研究发展历程、研究现状、研究…...

Hive调优集锦(2)

3.8 Join 优化 Join优化整体原则&#xff1a; 1、优先过滤后再进行 join 操作&#xff0c;最大限度的减少参与 join 的数据量 2、小表 join 大表&#xff0c;最好启动 mapjoin&#xff0c;hive 自动启用 mapjoin, 小表不能超过25M&#xff0c;可以更改 3、Join on的条件相同的…...

一文谈谈Git

"And if forever lasts till now Alright" 为什么要有git&#xff1f; 想象一下&#xff0c;现如今你的老师同时叫你和张三&#xff0c;各自写一份下半年的学习计划交给他。 可是你的老师是一个极其"较真"的人&#xff0c;发现你俩写的学习计划太"水&…...

嵌入式数据库之SQLite

1.SQLite简介 轻量化&#xff0c;易用的嵌入式数据库&#xff0c;用于设备端的数据管理&#xff0c;可以理解成单点的数据库。传统服务器型数据 库用于管理多端设备&#xff0c;更加复杂。 SQLite是一个无服务器的数据库&#xff0c;是自包含的。这也称为嵌入式数据库&#x…...

idea下tomcat运行乱码问题解决方法

idea虚拟机选项添加-Dfile.encodingUTF-8...

人工智能TensorFlow MNIST手写数字识别——实战篇

上期文章TensorFlow手写数字-训练篇,我们训练了我们的神经网络,本期使用上次训练的模型,来识别手写数字(本期构建TensorFlow神经网络代码为上期文章分享代码) http://scs.ryerson.ca/~aharley/vis/conv/ 0、插入第三方库 from PIL import Image# 处理图片 import tensorf…...

Vue 本地应用-计数器

逻辑是在点击按钮的时候执行&#xff0c;那么要为按钮绑定点击事件&#xff0c;整体语法如下&#xff1a; <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>首页</title><link href"" type"text/c…...

深入了解HTTP代理在网络爬虫与SEO实践中的角色

随着互联网的不断发展&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;成为各大企业和网站重要的推广手段。然而&#xff0c;传统的SEO方法已经难以应对日益复杂和智能化的搜索引擎算法。在这样的背景下&#xff0c;HTTP代理爬虫作为一种重要的工具&#xff0c;正在逐渐被…...

使用docker搭建nacos

使用docker搭建nacos docker搭建最新版nacosMySQL下简历nacos配置数据表拉取镜像创建挂载目录启动容器访问nacos docker搭建nacos 2.0版本 docker搭建最新版nacos 最近想在自己服务器上搭建一个nacos服务&#xff0c;以前一直在本地的windows上使用&#xff0c;而且使用着naco…...

flask中的常用装饰器

flask中的常用装饰器 Flask 框架中提供了一些内置的装饰器&#xff0c;这些装饰器可以帮助我们更方便地开发 Web 应用。以下是一些常用的 Flask 装饰器&#xff1a; app.route()&#xff1a;这可能是 Flask 中最常用的装饰器。它用于将 URL 路由绑定到一个 Python 函数&#x…...

SQL基础语法 | 增删改查、分组、排序、limit

Shell命令框和Navicat联合使用 一、数据库层面 创建数据库 postgres# CREATE DATABASE runoobdb;查看数据库 postgres# \l选择数据库 postgres# \c runoobdb删除数据库 postgres# DROP DATABASE runoobdb;二、表格层面 创建表格 CREATE TABLE table_name(字段名称 字段数据类型…...

QT: 用定时器完成闹钟的实现

闹钟项目&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimerEvent> #include <QTime> #include <QDebug> #include <QTextToSpeech> #include <QMessageBox> #include <QTimer>QT_BEGIN…...

Boyer-Moore 投票算法

这里先贴题目&#xff1a; Boyer-Moore 投票算法&#xff1a; 通俗点来讲&#xff0c;就是占领据点&#xff0c;像攻城那样&#xff0c;对消。 当你的据点有人时对消&#xff0c;无人时就占领。 这道题使用该算法可实现时间复杂度为O(n),空间复杂度为O(1)&#xff0c;接下来看…...

C# 翻转二叉树

226 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1] 示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#xff1a;…...

RocketMQ教程-(5)-功能特性-消费者分类

Apache RocketMQ 支持 PushConsumer 、 SimpleConsumer 以及 PullConsumer 这三种类型的消费者&#xff0c;本文分别从使用方式、实现原理、可靠性重试和适用场景等方面为您介绍这三种类型的消费者。 背景信息​ Apache RocketMQ 面向不同的业务场景提供了不同消费者类型&…...

Kafka原理剖析

一、简介 Kafka是一个分布式的、分区的、多副本的消息发布-订阅系统&#xff0c;它提供了类似于JMS的特性&#xff0c;但在设计上完全不同&#xff0c;它具有消息持久化、高吞吐、分布式、多客户端支持、实时等特性&#xff0c;适用于离线和在线的消息消费&#xff0c;如常规的…...

word怎么转换成pdf?分享几种转换方法

word怎么转换成pdf&#xff1f;将Word文档转换成PDF文件有几个好处。首先&#xff0c;PDF文件通常比Word文档更容易在不同设备和操作系统上查看和共享。其次&#xff0c;PDF文件通常比Word文档更难以修改&#xff0c;这使得它们在需要保护文件内容的情况下更加安全可靠。最后&a…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换

目录 关键点 技术实现1 技术实现2 摘要&#xff1a; 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式&#xff08;自动驾驶、人工驾驶、远程驾驶、主动安全&#xff09;&#xff0c;并通过实时消息推送更新车…...

Web中间件--tomcat学习

Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机&#xff0c;它可以执行Java字节码。Java虚拟机是Java平台的一部分&#xff0c;Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...