本章简言

上一章讲到关于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 源码分析——拦截器的机制的更多相关文章

  1. Struts2 源码分析-----拦截器源码解析 --- ParametersInterceptor

    ParametersInterceptor拦截器其主要功能是把ActionContext中的请求参数设置到ValueStack中,如果栈顶是当前Action则把请求参数设置到了Action中,如果栈顶 ...

  2. Spring AOP 源码分析 - 拦截器链的执行过程

    1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...

  3. springMVC源码分析--拦截器HandlerExecutionChain(三)

    上一篇博客springMVC源码分析--HandlerInterceptor拦截器调用过程(二)中我们介绍了HandlerInterceptor的执行调用地方,最终HandlerInterceptor ...

  4. Nacos 2.0源码分析-拦截器机制

    温馨提示: 本文内容基于个人学习Nacos 2.0.1版本代码总结而来,因个人理解差异,不保证完全正确.如有理解错误之处欢迎各位拍砖指正,相互学习:转载请注明出处. Nacos服务端在处理健康检查和心 ...

  5. Struts2 源码分析——DefaultActionInvocation类的执行action

    本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...

  6. Struts2 源码分析——Action代理类的工作

    章节简言 上一章笔者讲到关于如何加载配置文件里面的package元素节点信息.相信读者到这里心里面对struts2在启动的时候加载相关的信息有了一定的了解和认识.而本章将讲到关于struts2启动成功 ...

  7. Struts2 源码分析——配置管理之PackageProvider接口

    本章简言 上一章讲到关于ContainerProvider的知识.让我们知道struts2是如何注册相关的数据.也知道如何加载相关的配置信息.本章笔者将讲到如何加载配置文件里面的package元素节点 ...

  8. Struts2 源码分析——调结者(Dispatcher)之执行action

    章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...

  9. Struts2 源码分析——过滤器(Filter)

    章节简言 上一章笔者试着建一个Hello world的例子.是一个空白的struts2例子.明白了运行struts2至少需要用到哪一些Jar包.而这一章笔者将根据前面章节(Struts2 源码分析—— ...

随机推荐

  1. Oracle EBS - Doc

    Oracle EBS spec.: http://vianet/IT/IT%20Dept/IT%20Project%20Update2/Active%20Projects%20%20Manufactu ...

  2. sql字符串分组

    create function f_myWord(@s varchar(50)) returns varchar(50) as begin declare @i int set @i=1 while ...

  3. POI

    一.简介 POI(Point of Interest),中文可以翻译为“兴趣点”.在地理信息系统中,一个POI可以是一栋房子.一个商铺.一个邮筒.一个公交站等. 1.POI检索 百度地图SDK提供三种 ...

  4. linux内核分析作业5:分析system_call中断处理过程

    1.增加 Menu 内核命令行 调试系统调用. 步骤:删除menu git clone        (tab) make rootfs 这就是我们将 fork 函数写入 Menu 系统内核后的效果, ...

  5. 分分钟用上C#中的委托和事件

    每一个初学C#的程序猿,在刚刚碰到委托和事件的概念时,估计都是望而却步,茫然摸不到头脑的.百度一搜,关于概念介绍的文章大把大把的,当然也不乏深入浅出的好文章.可看完这些文章,大多数新手,估计也只是信心 ...

  6. [译]MVC网站教程(三):动态布局和站点管理

    目录 1.   介绍 2.   软件环境 3.   在运行示例代码之前(源代码 + 示例登陆帐号) 4.   自定义操作结果和控制器扩展 1)   OpenFileResult 2)   ImageR ...

  7. Tips for newbie to read source code

    This post is first posted on my WeChat public account: GeekArtT Reading source code is always one bi ...

  8. 读书笔记-you-don't-konw-js

    第一部分:作用域和闭包 不要满足于只是让代码正常工作,而是弄清楚为什么是这样 作用域是什么 定义的变量存储在哪里?程序是如何找到变量的?实现的 规则就是作用域 传统编译语言执行前的编译三步骤(p5) ...

  9. MyEclipse 2014(激活)

    激活 破解附件包下载:http://pan.baidu.com/s/1c27Dwe0 提取密码:qy38 详细破解步骤请参考:http://blog.my-eclipse.cn/myeclipse-2 ...

  10. 【开源】OSharp框架解说系列(1):总体设计及系列导航

    系列文章导航 [开源]OSharp框架解说系列(1):总体设计 [开源]OSharp框架解说系列(2.1):EasyUI的后台界面搭建及极致重构 [开源]OSharp框架解说系列(2.2):EasyU ...