论坛首页 Java企业应用论坛

Struts2的灵魂——Interceptor

浏览 28611 次
精华帖 (0) :: 良好帖 (12) :: 新手帖 (5) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-03-07   最后修改:2012-03-19

1.什么是拦截器:
拦截器是动态拦截Action调用的对象。它提供了一种机制使得开发者可以定义action执行之前或之后执行的代码,也可以在一个action执行前阻止其执行。

2.AOP:
提到拦截器,我们不得不提到AOP.
AOP(Aspect-Oriented Programming)译为:“面向切面编程”或者“面向方面编程”。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。拦截器的就是实现AOP的一种策略。
拦截器的工作原理简略图:


3.拦截器的作用:
  我们可以用Interceptor在Action的方法执行之前或者之后做一些处理,struts的核心功能正是由拦截器来实现的,比如捕获异常、数据校验、安全审查等等。

4.拦截器的工作原理:
Interceptor Stack(拦截器堆)中有顺序的存储着多个Interceptor,他们联接成链状,然后按照添加的顺序,依次调用。这里用到了递归调用,我认为这是设计者的聪明之处。
DefaultActionInvocation类持有拦截器链的引用,以及action的引用,是控制递归调用的重要类。
关于递归更深入的探讨,请猛击:http://candy-code.iteye.com/blog/1443427
下面我们就来模拟一下Interceptor的工作原理
5.Interceptor模拟:

Invocation.java



  
1.package com.interceptor.test;  
2.  
3.import java.util.ArrayList;  
4.import java.util.Iterator;  
5.import java.util.List;  
6./** 
7. * 模拟DefaultActionInvocation 
8. *  所有的拦截器存放在一个ArrayList中 
9. *  该类应当持有拦截器数组的引用和Action的引用 
10. */  
11.public class Invocation{  
12.    private List<Interceptor> interceptors = new ArrayList<Interceptor>();  
13.    private Iterator<Interceptor> interator;  
14.    private Action action;  
15.    /** 
16.     * 初始化拦截器和action 
17.     * 用new 模拟 
18.     * 实际上Invocation是从struts.xml读取内容,并初始化的 
19.     */  
20.    public Invocation(){  
21.        //按顺序加入Interceptor  
22.        interceptors.add(new FirstInterceptor());  
23.        interceptors.add(new SecondInterceptor());  
24.        interceptors.add(new ThirdInterceptor());  
25.        interator = interceptors.iterator();  
26.        action = new Action();  
27.    }  
28.    /** 
29.     * 这是一个递归方法 
30.     * 方法直接或者间接地调用自身即为递归。
31.     *invoke()调用intercept(),intercept()又调用invoke()  
32.     */  
33.    public void invoke(){  
34.        Interceptor interceptor;  
35.        //若链表中仍有Interceptor,则调用下一个Interceptor  
36.        if(interator.hasNext()){  
37.            interceptor = interator.next();  
38.            interceptor.intercept(this);  
39.        }  
40.        //链表中没有Interceptor了,则调用Action  
41.        else{  
42.            action.execute();  
43.        }  
44.    }  
45.}  


Interceptor.java
1.package com.interceptor.test;  
2.//模拟com.opensymphony.xwork2.interceptor.Interceptor接口  
3.//所有拦截器都应该实现该接口或者继承自Interceptor的子类  
4.public interface Interceptor {  
5.    //这是拦截器类的最重要的方法  
6.    //invocation用于存储拦截器链表  
7.    public void intercept(Invocation invocation);  
8.}  
 


FirstInterceptor.java
  
1.package com.interceptor.test;  
2.//第一个拦截器  
3.public class FirstInterceptor implements Interceptor{  
4.    @Override  
5.    public void intercept(Invocation invocation) {  
6.        //向控制输出信息,来模拟action调用前的处理工作  
7.        System.out.println("first interceptor -->be called");  
8.        //回调DefaultAcctionInvocation的方法  
9.        invocation.invoke();  
10.        //模拟action调用后的处理工作  
11.        System.out.println("first interceptor -->return");  
12.    }  
13.}  
 

SecondInterceptor.java
 
1.package com.interceptor.test;  
2.//第二个拦截器  
3.public class SecondInterceptor implements Interceptor{  
4.    @Override  
5.    public void intercept(Invocation invocation) {  
6.        System.out.println("Second interceptor -->be called");  
7.        invocation.invoke();  
8.        System.out.println("Second interceptor -->return");  
9.    }  
10.}  
 

ThirdInterceptor.java
 
1.package com.interceptor.test;  
2.//第三个拦截器  
3.public class ThirdInterceptor implements Interceptor{  
4.    @Override  
5.    public void intercept(Invocation invocation) {  
6.        System.out.println("Third interceptor -->be called");  
7.        invocation.invoke();  
8.        System.out.println("Third interceptor -->return");  
9.    }  
10.}  
 

Action.java
package com.interceptor.test;

public class Action {
	public String execute(){
		System.out.println("Action-->execute");
		return "success";
	}
}

Main.java
1.package com.interceptor.test;  
2.//用于启动模拟程序  
3.//模拟StrutsActionProxy的execute()方法  
4.public class Main {  
5.    // 创建Invocation,并调用其invoke()方法  
6.    public static void main(String[] args) {  
7.        new Invocation().invoke();  
8.    }  
9.}  
 


控制台输出结果为:
 
1.first interceptor -->be called  
2.Second interceptor -->be called  
3.Third interceptor -->be called  
4.Action-->execute  
5.Third interceptor -->return  
6.Second interceptor -->return  
7.first interceptor -->return  
 


相信看到输出结果之后,不用过多的解释,你也会对Interceptor的工作原理有更具体的了解了。

补充:本文中之所以只谈递归,不谈模式,是为了让读者更深刻更具象的了解底层原理。
   发表时间:2012-03-09  
通俗易懂,原来递归调用就这么回事,不错
0 请登录后投票
   发表时间:2012-03-09  
顺便请问下 LZ, struts2 的 拦截器 和 servlet标准中的 过滤器 在设计是是否相似 ? 都是在 某个过滤器链中 调用下一个链, 只是前者递归,后者顺序执行。
0 请登录后投票
   发表时间:2012-03-09   最后修改:2012-03-09
beyondyuefei 写道
顺便请问下 LZ, struts2 的 拦截器 和 servlet标准中的 过滤器 在设计是是否相似 ? 都是在 某个过滤器链中 调用下一个链, 只是前者递归,后者顺序执行。

Filter(过滤器)和Interceptor在设计上非常类似,都运用了递归的思想。
Filter接口最重要的方法是
doFilter(ServletRequest req, ServletResponse res, FilterChain chain){},其中chain就是过滤器链,
Filter的子类StrutsPrepareAndExecuteFilter在doFilter()中有这样一段代码:
if (!handled) {
   chain.doFilter(request, response);
} else {
  execute.executeAction(request, response, mapping);
}
可以看出,和Interceptor非常类似。
0 请登录后投票
   发表时间:2012-03-09  
写得不错 说明楼主对原理掌握得不错
0 请登录后投票
   发表时间:2012-03-09  
写的通俗易懂,lz对原理讲的很好
0 请登录后投票
   发表时间:2012-03-09  
Candy_Code 写道
beyondyuefei 写道
顺便请问下 LZ, struts2 的 拦截器 和 servlet标准中的 过滤器 在设计是是否相似 ? 都是在 某个过滤器链中 调用下一个链, 只是前者递归,后者顺序执行。

Filter(过滤器)和Interceptor在设计上非常类似,都运用了递归的思想。
Filter接口最重要的方法是
doFilter(ServletRequest req, ServletResponse res, FilterChain chain){},其中chain就是过滤器链,Filter的子类StrutsPrepareAndExecuteFilter在doFilter()中有这样一段代码:
if (!handled) {
   chain.doFilter(request, response);
} else {
  execute.executeAction(request, response, mapping);
}
可以看出,和Interceptor非常类似。


“其中chain就是过滤器链,Filter的子类”???谁说的?jdk API里可不是子类,虽然说设计成子类有更好的扩展,因为可以往里面直接添加FilterChain,但是事实就是没有。
0 请登录后投票
   发表时间:2012-03-09  
这个叫递归吗?command模式才对
0 请登录后投票
   发表时间:2012-03-09  
whiletrue 写道
这个叫递归吗?command模式才对


对,设计模式理解的很深刻。
0 请登录后投票
   发表时间:2012-03-09  
新手来学习下,还要再看两遍呢
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics