输入过滤器——InputFilter
一般情况下我们通过请求体读取器InputStreamInputBuffer获取的仅仅是源数据,即未经过任何处理发送方发来的字节。但有些时候在这个读取的过程中希望做一些额外的处理,并且这些额外处理可能是根据不同条件做不同的处理,考虑到程序解耦与扩展,于是引入过滤器(过滤器模式)——输入过滤器InputFilter。在读取数据过程中对于额外的操作只需要通过添加不同的过滤器即可实现,例如添加对http1.1协议分块传输的相关操作的过滤器。
如下图,在套接字输入缓冲装置中,从操作系统底层读取的字节会缓冲在buf中,请求行和请求头部被解析后缓冲区buf的指针指向请求体起始位置,通过请求体读取器InputStreamInputBuffer可进行读取操作,它会自动判定buf是否已经读完,读完则重新从操作系统底层读取字节到buf。当其他组件从套接字输入缓冲装置读取请求体时,装置将判定是否包含过滤器,假设有则通过一层层的过滤器完成过滤操作后才能到desBuf,这个过程就像被加入了一道道处理关卡,经过关卡都会被执行相应操作,最终完成源数据到目的数据的操作。
过滤器是一种设计模式,在Java的各种框架及容器都有频繁地使用以达到更好的扩展性和逻辑解耦。往下用一个例子看看过滤器如何工作。
① 输入缓冲接口InputBuffer,提供读取操作:
public interface InputBuffer {
public int doRead(byte[] chunk) throws IOException;
}
② 输入过滤器接口InputFilter,继承InputBuffer类,额外提供setBuffer方法设置前一个缓冲:
public interface InputFilter extends InputBuffer {
public void setBuffer(InputBuffer buffer);
}
③ 输入缓冲装置,模拟通过请求体读取器InputStreamInputBuffer从操作底层获取请求体字节数组,并且里面包含了若干个过滤器,缓冲装置在执行读取操作时会自动判断是否有过滤器,如存在则将读取后的字节在经过层层过滤,得到最终的目的数据。
public class InternalInputBuffer implements InputBuffer {
boolean isEnd = false;
byte[] buf = new byte[4];
protected int lastActiveFilter = -1;
protected InputFilter[] activeFilters = new InputFilter[2];
InputBuffer inputStreamInputBuffer = (InputBuffer) new InputStreamInputBuffer();
public void addActiveFilter(InputFilter filter) {
if (lastActiveFilter == -1) {
filter.setBuffer(inputStreamInputBuffer);
} else {
for (int i = 0; i <= lastActiveFilter; i++) {
if (activeFilters[i] == filter)
return;
}
filter.setBuffer(activeFilters[lastActiveFilter]);
}
activeFilters[++lastActiveFilter] = filter;
}
public int doRead(byte[] chunk) throws IOException {
if (lastActiveFilter == -1)
return inputStreamInputBuffer.doRead(chunk);
else
return activeFilters[lastActiveFilter].doRead(chunk);
}
protected class InputStreamInputBuffer implements InputBuffer {
public int doRead(byte[] chunk) throws IOException {
if (isEnd == false) {
buf[0] = 'a';
buf[1] = 'b';
buf[2] = 'a';
buf[3] = 'd';
System.arraycopy(buf, 0, chunk, 0, 4);
isEnd = true;
return chunk.length;
} else {
return -1;
}
}
}
}
④ 清理过滤器ClearFilter,负责将读取的字节数组中的字符a换成f:
public class ClearFilter implements InputFilter {
protected InputBuffer buffer;
public int doRead(byte[] chunk) throws IOException {
int i = buffer.doRead(chunk);
if (i == -1)
return -1;
for (int j = 0; j < chunk.length; j++)
if (chunk[j] == 'a')
chunk[j] = 'f';
return i;
}
public InputBuffer getBuffer() {
return buffer;
}
public void setBuffer(InputBuffer buffer) {
this.buffer = buffer;
}
}
⑤ 大写过滤器UpperFilter,负责将读取的字节数组全部变成大写:
public class UpperFilter implements InputFilter {
protected InputBuffer buffer;
public int doRead(byte[] chunk) throws IOException {
int i = buffer.doRead(chunk);
if (i == -1)
return -1;
for (int j = 0; j < chunk.length; j++)
chunk[j] = (byte) (chunk[j] - 'a' + 'A');
return i;
}
public InputBuffer getBuffer() {
return buffer;
}
public void setBuffer(InputBuffer buffer) {
this.buffer = buffer;
}
}
⑥ 测试类,创建输入缓冲装置,接着创建清理过滤器和大写过滤器,把它们添加到输入缓冲装置,执行读取操作,出来的就是经过两个过滤器处理后的数据了,结果为“FBFD”,如果有其他处理需求通过实现InputFilter接口编写过滤器并添加即可。
public class Test {
public static void main(String[] args) {
InternalInputBuffer internalInputBuffer = new InternalInputBuffer();
ClearFilter clearFilter = new ClearFilter();
UpperFilter upperFilter = new UpperFilter();
internalInputBuffer.addActiveFilter(clearFilter);
internalInputBuffer.addActiveFilter(upperFilter);
byte[] chunk = new byte[4];
try {
int i = 0;
while (i != -1) {
i = internalInputBuffer.doRead(chunk);
if (i == -1)
break;
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(new String(chunk));
}
}
由于篇幅问题,上面过程已经尽量模拟描述tomcat输入缓冲的工作流程,但实际使用的过滤器并非上面所述,主要包含四个过滤器:IdentityInputFilter、VoidInputFilter、BufferedInputFilter、ChunkedInputFilter。IdentityInputFilter过滤器在http包含content-length头部并且指定的长度大于0时使用,它将根据指定的长度从底层读取响应长度的字节数组,当读取足够数据后将直接返回-1,避免再次执行底层操作;VoidInputFilter过滤器用于拦截读取底层数据操作,当http不包含content-length头部时说明没有请求体,没必要执行读取套接字底层操作,所以用这个过滤器拦截;BufferedInputFilter过滤器负责读取请求体并将其缓存起来,后面读取请求体时直接从此缓冲区读取;ChunkedInputFilter过滤器专门用于处理分块传输,分块传输是一种数据传输机制,当没有指定content-length时可通过分块传输完成通信。
以上就是tomcat的套接字缓冲装置的过滤器的机制及其实现方法,并且简单介绍了tomcat中不同的过滤器的功能,过滤器模式让tomcat在后期程序扩展升级变得更容易。
喜欢研究java的同学可以交个朋友,下面是本人的微信号:
输入过滤器——InputFilter的更多相关文章
- Informatica 常用组件Source Qualifier之七 输入过滤器
通过输入源过滤器,可以降低 PowerCenter 查询的行数.如果在源过滤器中包括字符串 "WHERE" 或较大对象,PowerCenter 将使会话失败. 源限定符转换包括默 ...
- 75篇关于Tomcat源码和机制的文章
75篇关于Tomcat源码和机制的文章 标签: tomcat源码机制 2016-12-30 16:00 10083人阅读 评论(1) 收藏 举报 分类: tomcat内核(82) 版权声明:本文为 ...
- Angular JS 学习之过滤器
1.过滤器可以使用一个管道字符(|)添加到表达式和指令中: 2.AngularJS过滤器可用于转换数据: **currency:格式化数字为货币格式: **filter:从数组项中选择一个子集: ** ...
- AngularJS快速入门指南06:过滤器
thead>tr>th, table.reference>tbody>tr>th, table.reference>tfoot>tr>th, table ...
- angualrjs学习总结二(作用域、控制器、过滤器)
一:Scope简介 Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带.Scope 是一个对象,有可用的方法和属性.Scope 可应用在视图和控制器上. ...
- AngularJS(3)-过滤器
过滤器可以通过一个管道字符(|)和一个过滤器添加到表达式中.. 1.uppercase/lowercase 大小写过滤器 2.currency过滤器 3.向指令添加过滤器 过滤器可以通过一个管道字符( ...
- Wireshark安装、简单使用、过滤器简介
1.简介 Wireshark是一款非常著名的网络嗅探器,它的前身是Ethereal.Wireshark是一款免费的软件,只需要从官网下根据不同的系统(window,linux等)下载其对应的安装文件即 ...
- wireshark基础学习—第四部分wireshark过滤器总结
这两天一直在熟悉wireshark的过滤器语法规则,以前也接触过这个工具,但只是学校老师教的如何去选择一个接口进行抓取,以及如何去分析一个包的数据.可惜当时对此也没有过多深入.对于我当前,并未接触太多 ...
- AngularJS:过滤器
ylbtech-AngularJS:过滤器 1.返回顶部 1. AngularJS 过滤器 过滤器可以使用一个管道字符(|)添加到表达式和指令中. AngularJS 过滤器 AngularJS 过滤 ...
随机推荐
- WiFi认证中HTTPS重定向
问题描述 在引入WiFiDog实现上网认证功能中,有2个绕不过的问题:https重定向和Select检测问题,前者非要求用户访问80端口,后者导致效率较低下.就用户体验来说,https无法主动重定向非 ...
- PHP中利用DOM和simplxml读取xml文档
实例 用DOM获取下列xml文档中所有金庸小说的书名,该xml文档所在位置为 ./books.xml: <?xml version="1.0" encoding=" ...
- Spring 自带的定时任务Scheduled
1.注解@Scheduled 可以作为一个触发源添加到一个方法中,例如,以下的方法将以一个固定延迟时间5秒钟调用一次执行,这个周期是以上一个调用任务的完成时间为基准,在上一个任务完成之后,5s后再次执 ...
- tensorflow deepmath:基于深度学习的自动化数学定理证明
Deepmath Deepmath项目旨在改进使用深度学习和其他机器学习技术的自动化定理证明. Deepmath是Google研究与几所大学之间的合作. 免责声明: 该存储库中的源代码不是Google ...
- 【问底】徐汉彬:亿级Web系统搭建——单机到分布式集群
http://www.csdn.net/article/2014-11-06/2822529/3 大规模流量的网站架构,从来都是慢慢"成长"而来.而这个过程中,会遇到很多问题,在不 ...
- .NET中的各种池
在.NET中,常用到的池有四个:字符串拘留池.线程池 .应用程序池.数据库连接池. 字符串拘留池 在.NET中字符串是不可变对象,修改字符串变量的值会产生新的对象.为降低性能消耗及减小程序集大小,.N ...
- 深入浅出低功耗蓝牙(BLE)协议栈
深入浅出低功耗蓝牙(BLE)协议栈 BLE协议栈为什么要分层?怎么理解蓝牙"连接"?如果蓝牙协议只有ATT没有GATT会发生什么? 协议栈框架 一般而言,我们把某个协议的实现代码称 ...
- 0428-css样式
一.CSS样式表 引入的三种方式1.内联样式:标签内部 style2.内嵌样式:<head></head>标签内部(<style></sty ...
- 数据库的case when 使用实例
本文作者:苏生米沿 本文地址:http://blog.csdn.net/sushengmiyan/article/details/50471210 需求很简单,我有一个部门和部门的请假申请表.表数据简 ...
- IT男的别样人生,爱折腾,竟然辞职跑丽江去了
深圳待了4年,在深圳腾讯总部任职,北漂了5年多,任某知名团购公司CTO,有了孩子以后才知道自己想要什么 2015年4月,我和老婆还有6个月的儿子丽江游, 却在旅行的第四天, 买下了位于束河古镇正门的高 ...