组件开发系列--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"框架做支撑.如果你的项目中,也有基于此种场景的需求,可以考虑使用它. 在责任链模式里,很多对象由每一个对象对…...

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

云计算迎来中场战役,MaaS或将成为弯道超车“新赛点”
科技云报道原创。 没有人能预见未来,但我们可以因循常识,去捕捉技术创新演进的节奏韵脚。 2023年最火的风口莫过于大模型。 2022年底,由美国初创企业OpenAI开发的聊天应用ChatGPT引爆市场,生成式AI成为科技市场热点,…...

最新基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法
文献计量学是指用数学和统计学的方法,定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体,注重量化的综合性知识体系。特别是,信息可视化技术手段和方法的运用,可直观的展示主题的研究发展历程、研究现状、研究…...

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

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

嵌入式数据库之SQLite
1.SQLite简介 轻量化,易用的嵌入式数据库,用于设备端的数据管理,可以理解成单点的数据库。传统服务器型数据 库用于管理多端设备,更加复杂。 SQLite是一个无服务器的数据库,是自包含的。这也称为嵌入式数据库&#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 本地应用-计数器
逻辑是在点击按钮的时候执行,那么要为按钮绑定点击事件,整体语法如下: <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>首页</title><link href"" type"text/c…...

深入了解HTTP代理在网络爬虫与SEO实践中的角色
随着互联网的不断发展,搜索引擎优化(SEO)成为各大企业和网站重要的推广手段。然而,传统的SEO方法已经难以应对日益复杂和智能化的搜索引擎算法。在这样的背景下,HTTP代理爬虫作为一种重要的工具,正在逐渐被…...

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

flask中的常用装饰器
flask中的常用装饰器 Flask 框架中提供了一些内置的装饰器,这些装饰器可以帮助我们更方便地开发 Web 应用。以下是一些常用的 Flask 装饰器: app.route():这可能是 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: 用定时器完成闹钟的实现
闹钟项目: 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 投票算法
这里先贴题目: Boyer-Moore 投票算法: 通俗点来讲,就是占领据点,像攻城那样,对消。 当你的据点有人时对消,无人时就占领。 这道题使用该算法可实现时间复杂度为O(n),空间复杂度为O(1),接下来看…...

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

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

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

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

基于XDMA 中断模式的 PCIE3.0 QT上位机与FPGA数据交互架构 提供工程源码和QT上位机源码
目录 1、前言2、我已有的PCIE方案3、PCIE理论4、总体设计思路和方案图像产生、发送、缓存数据处理XDMA简介XDMA中断模式图像读取、输出、显示QT上位机及其源码 5、vivado工程详解6、上板调试验证7、福利:工程代码的获取 1、前言 PCIE(PCI Express&#…...

Vue 中通用的 css 列表入场动画效果
css 代码 .gradientAnimation {animation-name: gradient;animation-duration: 0.85s;animation-fill-mode: forwards;opacity: 0; }/* 不带前缀的放到最后 */ keyframes gradient {0% {opacity: 0;transform: translate(-100px, 0px);}100% {opacity: 1;transform: translate…...

微分流形2:流形上的矢量场和张量场
来了来了,切向量,切空间。流形上的所有的线性泛函的集合,注意是函数的集合。然后取流形上的某点p,它的切向量为,线性泛函到实数的映射。没错,是函数到实数的映射,是不是想到了求导。我们要逐渐熟…...

C++数组、向量和列表的练习
运行代码: //C数组、向量和列表的练习 #include"std_lib_facilities.h"int main() try {int ii[10] { 0,1,2,3,4,5,6,7,8,9 };for (int i 0; i < 10; i)//把数组中的每个元素值加2ii[i] 2;vector<int>vv(10);for (int i 0; i < 10; i)vv…...

视频剪辑矩阵分发系统Unable to load FFProbe报错技术处理?
问题一 报错处理 对于视频剪辑矩阵分发系统中出现的“Unable to load FFProbe”报错问题,可以采取以下技术处理措施进行解决。 1.检查系统中是否正确安装了FFProbe工具,并确保其路径正确配置。 2.检查系统环境变量是否正确设置,包括FFPr…...

Docker轻量级可视化工具Portainer
Portainer是一个轻量级的管理UI界面,用于管理Docker容器、镜像、卷和网络。它支持端口映射、容器启动、停止、删除、日志查看等功能,同时也提供了可视化的监控和统计功能,可以快速轻松的管理多个Docker主机。Portainer不需要额外安装依赖&…...

功率放大器在电光调制中的应用有哪些
电光调制是一种利用光电效应将电信号转化为光信号的技术。在实现电光调制的过程中,功率放大器作为一个重要的组件,具有对输入电信号进行放大和控制的功能。本文将介绍功率放大器的基本原理、特点以及在电光调制中的应用。 基本原理 功率放大器是一种能够…...

MyBatis入门程序
1.MyBatis 入门程序开发步骤 SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话) SqlSessionFactory:是“生产”SqlSession的“工厂”。 工厂模式:如果创建某一个对象ÿ…...

C++快速切换 头文件和源文件
有没有一种快速的方法 , 将头文件中的声明 直接在源文件中自动写出来, 毕竟头文件中已经有声明了, 我只需要写具体实现就行了,没有必要把声明的部分再敲一遍在 Visual Studio 中,你可以使用快速生成函数定义的功能来实…...

对原型、原型链的理解
在 JavaScript 中是使用构造两数来新建一个对象的,每一个构造函数的内部都有一个 prototype 属性,它的属性值是一个对象,这个对象包含了可以由该构造西数的所有实例共享的属性和方法。当使用构造函数新建一个对象后,在这个对象的内…...