Struts2 源码分析——拦截器的机制
| 本章简言 |
上一章讲到关于action代理类的工作。即是如何去找对应的action配置信息,并执行action类的实例。而这一章笔者将讲到在执行action需要用到的拦截器。为什么要讲拦截器呢?可以这样子讲吧。拦截器的应用是sturts2核心的亮点之一。如果不明白拦截器是什么的话,那么你相当于没有学习过struts2。笔者本来想直接讲这一章的知识点。可是又怕读者可能对拦截器没有一个概念化的理解。为什么这么讲呢?struts2在设计拦截器这一个部分的内容。在笔者看来事实是以AOP为核心思想来设计的。所以就是必须先理解一下AOP思想到底是什么东东。只有这样子才能更好的去理解struts2的拦截器。
| AOP思想 |
AOP思想的全名为Aspect Oriented Programming。即是面向切面编程。相信读者者听过OOP(Object-Oriented Programing,面向对象编程)。笔者也认AOP是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。为什么笔者这边用“也”这个字呢?笔者不是一个喜欢吹牛的人。会就是会,不会就是不会。网络上有很多关于AOP思想的资料,笔者就是通过这些资料学习的,也认同AOP是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。所以笔者这里也只是简章的讲解一下AOP思想。希望读者见谅。
什么叫做面向切面编程呢?如果用专业的角度来讲切面叫作Aspect。struts2拦截器相关的类就是切面(Aspect)。完了。什么东东啊!没事。笔者就土话来讲吧。对于传统面向对象编程来讲,执行业务代码一般都会在方法里面。这一点大家都知道。相信大家也知道在执行相关业务代码之前也会执行对应的验证代码。作为一个软件设计师在设计整个构架的时候,一定会理解业务并把业务划分为几个独立的模块。而每模块都一定会有相关的验证代码。如什么数据不能为空等相关验证代码。甚至有一些软件系统希望有对应的日志跟踪的时候,对应的日志代码也要写入进去。如图下。

可以说图上是从纵向角度来看。把业务划分出多个独立业务模块,每一个业务模块都有相应的数据验证和日志记录。笔者认为AOP思想则是要横向角度来看。什么说呢?笔者在上面的图片加入横向角度之后会是一个什么样子。如图下

当笔者把横向角度加入之后,就是会发现把业务模块相关代码和其他代码进行了分离独立起来了。如上面图片中的图1就是加入之后的状态了。那么笔者是什么知道要这样子分呢?主要是关注点。即是横向关注点。笔者希望把业务代码和其他代码进行分离独立起来。这就是笔者的关注点(这里的业务代码是总业务代码。即是把所有的业务代码看作一个整体)。而图片中的图2便是最后的结果。为什么三块验证代码最后变成一个块呢?举个简单的例子吧。笔者相信有工作经验的程序员都会经验过非空的代码或是非空并没有特殊的字符等相关的验证吧。难道你不觉得这块的代码逻辑是可以共通的吗?当然笔者也想过这样子的问题——新一个专门用来实现验证功能的类不就行了吗?没有错。是可以的。可是AOP思想的核心笔者认为不是在这里。他的目标是让业务模块去选择自己对应的验证代码。验证代码就是切面(Aspect)。什么意思呢?当业务模块相关代码和其他代码进行了分离独立的时候。其他代码这个部分事实上是可以进行重组和切分。比如:日志相关的代码变成一个日志切面(只是一个类)。性能相关代码变成一个性能切面。各个切面之间是相互独立的。最后就是变成了根据不同的业务模块去选择不同需要的切面。图片上的图2就是最后笔者得出来的结果。当然笔者也不敢说自己是对的。个人看法而以。
对于上面AOP理解也是笔者自己的个人看法而以。笔者也不敢说是对的。每一个人的理解是不一样子的。也不一定见得读者的理解是错的。显然笔者认为AOP真的很不错。纵向把业务划分出模块。横向把代码划出模块。
| 拦截器的执行机制 |
struts2的拦截器笔者认为就是AOP思想的一种体现。在进入action类实例之前必须先执行相关拦截器。即是拦截器相当于AOP思想里面的切面。把用户action类和拦截器分离独立,就像笔者上面讲的横向关注点一样子。因为大部分的用户action类是跟业务有关系的。所以strust2里面有很多拦截器。不同的action类可能会选择不同的拦截器。当然也有一些默认必须有的拦截器。从《Struts2 源码分析——Action代理类的工作》章节里面我们知道执行action请求是在DefaultActionInvocation类的invoke方法。可以这样子讲吧。一切都从这个方法开始的。如下
DefaultActionInvocation类:
public String invoke() throws Exception {
String profileKey = "invoke: ";
try {
UtilTimerStack.push(profileKey);
if (executed) {
throw new IllegalStateException("Action has already executed");
}
if (interceptors.hasNext()) {//获得一个拦截器
final InterceptorMapping interceptor = interceptors.next();
String interceptorMsg = "interceptor: " + interceptor.getName();
UtilTimerStack.push(interceptorMsg);
try {
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);//执行拦截器
} finally {
UtilTimerStack.pop(interceptorMsg);
}
} else {
resultCode = invokeActionOnly();
}
// this is needed because the result will be executed, then control will return to the Interceptor, which will
// return above and flow through again
if (!executed) {
if (preResultListeners != null) {
LOG.trace("Executing PreResultListeners for result [{}]", result);
for (Object preResultListener : preResultListeners) {
PreResultListener listener = (PreResultListener) preResultListener;
String _profileKey = "preResultListener: ";
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult(this, resultCode);
}
finally {
UtilTimerStack.pop(_profileKey);
}
}
}
// now execute the result, if we're supposed to
if (proxy.getExecuteResult()) {
executeResult();
}
executed = true;
}
return resultCode;
}
finally {
UtilTimerStack.pop(profileKey);
}
}
上面的红色的代码是这个方法的核心点之一。也是实现AOP思想的代码亮点。让我们看一下红色代码做什么?判断interceptors是否有拦截器。如果没有就直接执行invokeActionOnly方法。即是执行action类实例对应的方法。如果有就获得拦截器并执行拦截器(执行intercept方法)。好了。关键点就在这个执行拦截器身上。即是执行intercept方法。intercept方法有一个参数就是DefaultActionInvocation类的接口。这个参数让struts2的AOP思想能够进行。为什么这样子讲呢?不清楚读者有没有想过。为什么这边判断拦截器是用if而不是用for 或是 while呢?必竟拦截器不只一个。我们都清楚AOP的目标就是让业务模块选择对应的切面。那么就有可能存在多个拦截器。这也是为什么亮点的原因了。看一下拦截器的代码就知道了。如下
LoggingInterceptor类:
public String intercept(ActionInvocation invocation) throws Exception {
logMessage(invocation, START_MESSAGE);
String result = invocation.invoke();
logMessage(invocation, FINISH_MESSAGE);
return result;
}
上面的源码是笔者从多个拦截器中选择一个比较简单的来看。不清楚你们明白了没有。红色的代码已经很明确说明了一件事情。拦截器开始的时候,执行相关的拦截器逻辑,然后又重新调用DefaultActionInvocation类的invoke方法。从而获得下一个拦截器。就是这样子下一个拦截器又开始执行自己的intercept方法。做了相关的拦截器逻辑之后。又一次重新调用DefaultActionInvocation类的invoke方法。又做了相似的工作。只到没有了拦截器,执行用户action类实例的方法并返回结果。有了结果之后,就开始续继执行当前上一个拦截器的后半部分代码。只到返回到最开始的拦截器执行后半部分的代码。如果硬要说一个相似的专业词语的话。笔者会想到方法叠带。
笔者心里面对这一部分的做法一直很喜欢。当然也不少人不会认同笔者的观念。可以看得出来AOP思想把个个切面和业务模块处理的非常好。切面和业务模块又是独立的互不影响。同时可以让开发人员更加关注对应的业务逻辑。
注意:学习这一部分最好结合《Struts2 源码分析——核心机制》的核心机制的图片。这样子会更好理解。
| 本章总结 |
本章主要是讲到关于拦截器的运行机制。知道了struts2是如果进行处理拦截器和action类实例之间关系。同时也了解了相关AOP思想。
Struts2 源码分析——拦截器的机制的更多相关文章
- Struts2 源码分析-----拦截器源码解析 --- ParametersInterceptor
ParametersInterceptor拦截器其主要功能是把ActionContext中的请求参数设置到ValueStack中,如果栈顶是当前Action则把请求参数设置到了Action中,如果栈顶 ...
- Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
- springMVC源码分析--拦截器HandlerExecutionChain(三)
上一篇博客springMVC源码分析--HandlerInterceptor拦截器调用过程(二)中我们介绍了HandlerInterceptor的执行调用地方,最终HandlerInterceptor ...
- Nacos 2.0源码分析-拦截器机制
温馨提示: 本文内容基于个人学习Nacos 2.0.1版本代码总结而来,因个人理解差异,不保证完全正确.如有理解错误之处欢迎各位拍砖指正,相互学习:转载请注明出处. Nacos服务端在处理健康检查和心 ...
- Struts2 源码分析——DefaultActionInvocation类的执行action
本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...
- Struts2 源码分析——Action代理类的工作
章节简言 上一章笔者讲到关于如何加载配置文件里面的package元素节点信息.相信读者到这里心里面对struts2在启动的时候加载相关的信息有了一定的了解和认识.而本章将讲到关于struts2启动成功 ...
- Struts2 源码分析——配置管理之PackageProvider接口
本章简言 上一章讲到关于ContainerProvider的知识.让我们知道struts2是如何注册相关的数据.也知道如何加载相关的配置信息.本章笔者将讲到如何加载配置文件里面的package元素节点 ...
- Struts2 源码分析——调结者(Dispatcher)之执行action
章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...
- Struts2 源码分析——过滤器(Filter)
章节简言 上一章笔者试着建一个Hello world的例子.是一个空白的struts2例子.明白了运行struts2至少需要用到哪一些Jar包.而这一章笔者将根据前面章节(Struts2 源码分析—— ...
随机推荐
- 浅谈P2P金融
自从李总理开发互联网大会,提出“互联网+”,好像与互联网相在的所有事情都火起来了.上至80岁的老头,下至十多岁的孩童,都知道了这个词“互联网+”.虽然大家可能对”互联网+“的概念都只是一支半解,但是像 ...
- Amoeba -- 阿里巴巴工程师的开源项目之一陈思儒
http://www.kuqin.com/opensource/20081023/24026.html 个人博客 http://dbanotes.net/web/page/44 阿里巴巴分布式服务框架 ...
- c#多线程介绍(上)
转载原文:这里是链接内容 转载原文:这里写链接内容 转载原文:这里写链接内容 (重要事情说三遍) 引言 本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个 ...
- [转]各种移动GPU压缩纹理的使用方法
介绍了各种移动设备所使用的GPU,以及各个GPU所支持的压缩纹理的格式和使用方法.1. 移动GPU大全 目前移动市场的GPU主要有四大厂商系列:1)Imagination Technologies的P ...
- 支持向量机(SVM)复习总结
摘要: 1.算法概述 2.算法推导 3.算法特性及优缺点 4.注意事项 5.实现和具体例子 6.适用场合 内容: 1.算法概述 其基本模型定义为特征空间上的间隔最大的线性分类器,即支持向量机的学习策略 ...
- iOS-网络处理
1.iOS-网络基础 2.iOS-网络处理框架AFN 3.iOS-网络爬虫
- ArchLinux安装指南
将ArchLinux作为进阶Linux发行版,主要看重滚动更新和深入理解Linux的安装过程. 由于是新手,所以先选择在公司电脑上用VMware来安装.然后渐进到借助U盘在win10笔记本上安装双系统 ...
- 深入浏览器兼容 细数jQuery Hooks 属性篇
关于钩子:http://www.cnblogs.com/aaronjs/p/3387906.html 本章的目的很简单,通过钩子函数更细节的了解浏览器差异与处理方案, 版本是2.0.3所以不兼容ie6 ...
- 12款非常精致的免费 HTML5 & CSS3 网站模板
01. Joefrey Mahusay 很炫的单页网站模板,基于 HTML5 & CSS3 制作,适合用于设计师个人简历.摄影师和平面设计师的个人作品展示. 演示 下载 02. Folder ...
- 动态给div中新增html
小颖最近接触的项目中用到了 innerHTML 所以小颖今天就自己做了个demo,当当当当代码请看下方: 页面效果: