1、拦截器采用的动态代理模式实现的在目标执行之前或之后插入必要的辅助业务。其实采用的是一种AOP的思想,来降低系统耦合。

下面我们介绍一个动态代理:

Java中提供一种动态代理的实现模式,我们用一个例子实现动态代理的演示:

涉及到代理就肯定要有:目标对象代理对象拦截器

三者之间的关系:代理对象代理目标对象在目标对象执行之前或之后加入拦截器的功能。

首先我们创建一个目标对象:

1.1.定义一个接口

package com.snt.struts2.interceptor;
public interface ITargetInterface {
         publicvoid doSomething();
}

1.2.定义一个目标对象实现目标对象接口 [目标对象一定要实现一个接口]

package com.snt.struts2.interceptor;
public class Target implementsITargetInterface {
         //拦截的目标对象
         publicvoid doSomething() {
                   System.out.println("dosomething...");
         }
}

1.3.定义一个拦截器(这里我们的拦截器比较简单,就是一个普通在类,定义了一在目标对象调用之前工之后要执行的操作) [定义的两个方法,代表在目标对象调用之前和之后要执行的操作]

package com.snt.struts2.interceptor;
public class Interceptor {
         publicvoid befor() {
                   System.out.println("before");
         }
         publicvoid after() {
                   System.out.println("after");
         }
}

1.4.下面来实现代理,如何为目标对象产生一个代理对象呢?java为我们提供了一定代理机制!

Javajava.lang.reflect包下面提供了一个Proxy 类,这个类可以为一个目标类产生代理类。

使用以下更简单的方法:

ITargetInterface iTargetInterface = (ITargetInterface)Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { ITargetInterface.class },handler);

第一个参数:目标类的加载器;

第二个参数:目标实现的接口集合;

第三个参数:代理类的调用处理程序对象。


动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。

代理接口:是代理类实现的一个接口。

代理实例:是代理类的一个实例。每个代理实例都有一个关联的调用处理程序对象,它可以实现接口InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的Invoke方法,并传递代理实例、识别调用方法的java.lang.reflect.Method 对象以及包含参数的 Object类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。


对于我们这个例子:也要先创建一个代理类的调用处理程序,如下:


1.5.创建一个MyHandler,实现InvocationHandler接口,实现其中的invoke()方法,代码如下:

package com.snt.struts2.interceptor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyHandler implementsInvocationHandler {
         privateObject obj;// 目标对象
         //拦截器对象
         privateInterceptor interceptor = new Interceptor();
         //注入目标对象
         publicvoid setObject(Object obj) {
                   this.obj= obj;
         }
         publicObject invoke(Object proxy, Method method, Object[] args)
                            throwsThrowable {
                   Objectresult = null;
                   //调用目标方法前执行的操作
                   interceptor.befor();
                   result= method.invoke(obj, args);
                   //调用目标方法后执行的操作
                   interceptor.after();
                   returnresult;
         }
}


1.6.创建一个产生代理的工厂类,创建一个MyProxy,代码如下:


package com.snt.struts2.interceptor;
import java.lang.reflect.Proxy;
/**
 * 产生一个代理
 */
public class MyProxy {
         //根据一个目标类产生一个代理对象
         publicObject getProxy(Object object) {
                   MyHandlermh = new MyHandler();
                   mh.setObject(object);
                   returnProxy.newProxyInstance(Target.class.getClassLoader(), object
                                     .getClass().getInterfaces(),mh);
         }
}

创建一个测试类,为目标对象产生代理,调用其方法,查看执行效果:

package com.snt.struts2.interceptor;
public class Client {
         publicstatic void main(String[] args) {
                   ITargetInterfacetarget = new Target();
                   MyProxymp = new MyProxy();
                   ITargetInterfaceproxy = (ITargetInterface) mp.getProxy(target);
                   proxy.doSomething();
         }
}

运行结果:在调用目标类方法doSomethin()之前和之后插入拦截的功能。


2OK,上面讲的一个采用我们自定义拦截器的方式实现在目标拦截的功能,下面的我们看一下Struts2中如何使用拦截器。Struts2中拦截器是一个实现了Interceptor接口的类,下面我们来定义一具体的拦截器,实现Action的拦截。

定义一个MyInterceptor ,代码如下:

package com.snt.struts2.interceptors;
importcom.opensymphony.xwork2.ActionInvocation;
importcom.opensymphony.xwork2.interceptor.Interceptor;
public class MyInterceptor implementsInterceptor {
         privateString hello;
         publicString getHello() {
                   returnhello;
         }
         publicvoid setHello(String hello) {
                   this.hello= hello;
         }
         publicvoid destroy() {
                   System.out.println("destory()");
         }
         publicvoid init() {
                   System.out.println("init()");
                   System.out.println(hello);
         }
         /**
          * 拦截Action
          */
         publicString intercept(ActionInvocation invocation) throws Exception {
                   System.out.println("interceptor");
                   Stringresult = invocation.invoke();
                   System.out.println("finshed");
                   returnresult;
         }
}

拦截器中主要实现interceptor()方法,interceptor中调用目标对象前后加入你定义的业务操作。

OK,拦截器配置好之后,如何让其生效呢?需要在struts.xml 文件中配置。

struts.xml 配置文件中,Struts2会为每个Action加上一具默认在拦截器配置,那就是struts-default.xml中的<interceptor-ref  name="defaultStack" />,在Struts2拦截器存在两种概念,一种是拦截器,一种拦截链,拦截链就是一系列的拦截器连接在一起进行对目标拦截,而Struts2并没有把两种概念进行区别,而是都它们都当成拦截器对待,因此在拦截器的定义标签<interceptors></interceptors>中,定义、引用拦截器和拦截链是同样的方式。


对于上面的拦截器,我们需要在struts.xml文件中如下配置


方式1

<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
   "-//Apache Software Foundation//DTD Struts Configuration2.0//EN"
   "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
         <packagename="struts2" extends="struts-default">
                   <!--配置拦截器 -->
                   <interceptors>
                            <!--自定义拦截器 -->
                            <interceptorname="myInterceptor"class="com.snt.struts2.interceptors.MyInterceptor">
                                     <paramname="hello">world</param>
                            </interceptor>
                   </interceptors>
                   <actionname="point" class="com.snt.struts2.action.PointAction">
                            <resultname="success">output.jsp</result>
                            <resultname="input">input.jsp</result>
                            <!--引用上面配置的拦截器 -->
                            <interceptor-refname="myInterceptor">
                                     <paramname="hello">welcom</param>
                            </interceptor-ref>
                            <interceptor-refname="defaultStack"></interceptor-ref>
                   </action>
         </package>
</struts>

我们将一个拦截配置在point这个Action中,说明我们要使用这个拦截器来拦截这个Action,见红色的字体,拦截器配置中间我们还加了一个参数,struts2会自动将该参数的值加载到拦截器中对应属性的值。OK,这样配置好了,运行程序测试,发现结果数据是错误的。这是为什么呢?

前面说过Struts2会为每个Action应用一个默认的拦截器,这个拦截器是在struts-default.xml文件中配置的,而我们的struts.xml开关又出现这样的配置

<packagename="struts2" extends="struts-default">

说明我们的配置继承了struts-default.xml中的配置。

当我们如下配置文件中那样配置后,默认的配置就会被引用了,这是Struts2本身所有实现的,当我们为一个Action配置了拦截器时,默认的拦截器就会失效,但是Struts2本身的一些功能,比如说参数自动赋值又是依赖配置的默认拦截器实现,所有应用程序会出错。这时需要我们手动将默认的拦截器引用进来,再为这项Action加入默认拦截器:

<interceptor-refname="defaultStack"/>

另外要注意:如果拦截器声明时和引用时都配置了参数,那最引用时的参数配置是有效的。

比如:上面的配置在配置拦截器时给hello参数传一个”world”,但在下面action中使用拦截器时,又给参数hello配置了"welcome”值,最终使用的将是action使用时拦截器时配置的值。


方式2

我们为简便,还可以定义一个拦截链,上面说过,拦截链和拦截器一样,所以我们也在<interceptors></interceptors>标签中配置拦截链。

<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
   "-//Apache Software Foundation//DTD Struts Configuration2.0//EN"
   "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
         <packagename="struts2" extends="struts-default">
                   <!--配置拦截器 -->
                   <interceptors>
                            <!--自定义拦截链 -->
                            <interceptor-stackname="myStack">
                                     <!-- 执行顺序与配置顺序有关 -->
                                     <interceptor-refname="myInterceptor"class="com.snt.struts2.interceptors.MyInterceptor"></interceptor-ref>
                                     <interceptor-refname="myInterceptor2"class="com.snt.struts2.interceptors.MyInterceptor2"></interceptor-ref>
                                     <interceptor-refname="defaultStack"></interceptor-ref>
                            </interceptor-stack>
                   </interceptors>
                   <!--设置默认拦截链,一个package下只能配置一个,应用所有的没有配置拦截器或拦截链的Action -->
                   <default-interceptor-refname="myStack"></default-interceptor-ref>
                   <actionname="point" class="com.snt.struts2.action.PointAction">
                            <resultname="success">output.jsp</result>
                   </action>
         </package>
</struts>


上面我们配置一个拦截链,但是我们并没有写在下面的action中,运行程序PointAction还是被拦截了。这是为什么呢?看上面有这样一句配置:


<default-interceptor-refname="myStack"></default-interceptor-ref>


这句配置是定义了一个默认拦截链或拦截器,这个拦截就像struts-default.xml文件中的defaultStack一样,我们在我们的配置中也可以定义一个默认拦截器来拦截所有的action。但是还是要注意一点,当一个action引用了其它的拦截器或拦截链时,我们定义的拦截器也会失效。而且默认的拦截器一个包中只能声明一个。


还要注意的是:我们定义多个拦截器后它们的执行顺序,这个顺序和他们在配置中声明的顺序是有关的,先声明的先执行。


拦截器中执行的操作分两种,一种是目标对象调用前执行的操作,一种目标对象调用后执行的操作。这个也是有顺序的。如果有两个拦截器,那么执行的顺序就是:第一个拦截器执行前操作——第二个拦截器执行前操作——目标对象的调用——第二个拦截器执行后操作——第一个拦截器执行后操作。

上面代表拦截器A要在目标对象执行前调用beforeA()在目标对象调用后执行afterA(),拦截器B同样。那么执行过程拦截器的调用情况如下:

beforeA()

beforeB()

目标对象的调用

afterB()

afterA()


上面的我们定义的拦截器类MyInterceptor里面有三个方法(这是Interceptor接口中的三个方法),即:

init();

destory();

interceptor(ActionInvocation invocation)              【我们真正要实现的方法】

但是init()destory()方法我们不经常用,但是双必须把它继承下来,看起不是很爽,查看API我们会找到一个AbstrctInterceptor类,这个类是一个抽象类,它实现了init()destory()【其实两个方法并没有没真正做什么,是空实现】,interceptor() 方法是抽象的,所以我通常自定义拦截器时,可以实现AbstractInterceptor类,着重写interceptor()方法即可。


OK,上面讲的都是针对Action的拦截,Struts2中还有一种拦截器是针对方法的拦截器。


Struts2中有一个MethodFilterInterceptor的拦截器,它继承了AbstractInterceptor类,可以对方法进行拦截。这个类也是个抽象类,其中有doInterceptor()方法是个抽象方法,我们只需要实现这个方法即可。


比如:我们需要使用一个拦截器拦截一个action中的login()方法,而不拦截器action中的logout()方法,看拦截器如何实现:


MethodFileterInterceptor 拦截器是通过指定

// 不需要拦截的方法名列表

protected Set<String> excludeMethods= Collections.emptySet();


// 需要拦截的方法名列表

protected Set<String> includeMethods= Collections.emptySet();


以上两个属性,一个是指定哪些方法需要拦截,另一个是指定哪些方法不需要拦截。在配置拦截器时需要配置这两个参数。


我们行定义一个方法拦截器,代码如下:MyInterceptor3


package com.snt.struts2.interceptors;
import com.opensymphony.xwork2.ActionInvocation;
importcom.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
public class MyInterceptor3 extendsMethodFilterInterceptor {
         @Override
         protectedString doIntercept(ActionInvocation invocation) throws Exception {
                   System.out.println("myInterceptor3");
                   Stringresult = invocation.invoke();
                   returnresult;
         }
}


下面我们配置这个方法拦截器:


<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
   "-//Apache Software Foundation//DTD Struts Configuration2.0//EN"
   "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
         <packagename="struts2" extends="struts-default">
                   <!--配置一个拦截器 -->
                   <interceptors>
                            <!--自定义拦截器 -->
                            <interceptorname="myInterceptor3"class="com.snt.struts2.interceptors.MyIntercepto3" />
                            <interceptorname="myInterceptor"class="com.snt.struts2.interceptors.MyInterceptor">
                                     <paramname="hello">world</param>
                            </interceptor>
                            <!--自定义拦截链 -->
                            <interceptor-stackname="myStack">
                                     <interceptor-refname="myInterceptor"></interceptor-ref>
                                     <interceptor-refname="defaultStack"></interceptor-ref>
                            </interceptor-stack>
                   </interceptors>
                   <!--设置默认拦截链,一个package下只能配置一个,应用所有的没有配置拦截器或拦截链的Action -->
                   <default-interceptor-refname="myStack"></default-interceptor-ref>
                   <actionname="point" class="com.snt.struts2.action.PointAction">
                            <interceptor-refname="myStack" />
                            <interceptor-refname="myInterceptor3">
                                     <!--同时指定拦截方法和排除方法时,拦截方法的级别高 -->
                                     <paramname="includeMethods">execute,login</param>
                                     <paramname="excludeMethods">logout</param>
                            </interceptor-ref>
                   </action>
         </package>
</struts>


注意:同时指定拦截方法和排除方法时,拦截方法的级别高。


上面举的例子拦截器中东西都比较简单,真正在开发时候需要根据具体的业务来编写拦截器的内容!所以大家在实际项目中多多练习便会慢慢的掌握拦截器,另外Struts2中自带了的拦截器、拦截链(在struts-default.xml中),大家还是应该了解下的,具体如下:


拦截器

名字

说明

Alias Interceptor

alias

在不同请求之间将请求参数在不同名字件转换,请求内容不变

Chaining Interceptor

chain

让前一个Action的属性可以被后一个Action访问,现在和chain类型的result<result type=chain>)结合使用。

Checkbox Interceptor

checkbox

添加了checkbox自动处理代码,将没有选中的checkbox的内容设定为false,而html默认情况下不提交没有选中的checkbox

Cookies Interceptor

cookies

使用配置的name,value来是指cookies

Conversion Error Interceptor

conversionError

将错误从ActionContext中添加到Action的属性字段中。

Create Session Interceptor

createSession

自动的创建HttpSession,用来为需要使用到HttpSession的拦截器服务。

Debugging Interceptor

debugging

提供不同的调试用的页面来展现内部的数据状况。

Execute and Wait Interceptor

execAndWait

在后台执行Action,同时将用户带到一个中间的等待页面。

Exception Interceptor

exception

将异常定位到一个画面

File Upload Interceptor

fileUpload

提供文件上传功能

I18n Interceptor

i18n

记录用户选择的locale

Logger Interceptor

logger

输出Action的名字

Message Store Interceptor

store

存储或者访问实现ValidationAware接口的Action类出现的消息,错误,字段错误等。

Model Driven Interceptor

model-driven

如果一个类实现了ModelDriven,将getModel得到的结果放在Value Stack中。

Scoped Model Driven

scoped-model-driven

如果一个Action实现了ScopedModelDriven,则这个拦截器会从相应的Scope中取出model调用ActionsetModel方法将其放入Action内部。

Parameters Interceptor

params

将请求中的参数设置到Action中去。

Prepare Interceptor

prepare

如果Acton实现了Preparable,则该拦截器调用Action类的prepare方法。

Scope Interceptor

scope

Action状态存入sessionapplication的简单方法。

Servlet Config Interceptor

servletConfig

提供访问HttpServletRequestHttpServletResponse的方法,以Map的方式访问。

Static Parameters Interceptor

staticParams

struts.xml文件中将<action>中的<param>中的内容设置到对应的Action中。

Roles Interceptor

roles

确定用户是否具有JAAS指定的Role,否则不予执行。

Timer Interceptor

timer

输出Action执行的时间

Token Interceptor

token

通过Token来避免双击

Token Session Interceptor

tokenSession

Token Interceptor一样,不过双击的时候把请求的数据存储在Session

Validation Interceptor

validation

使用action-validation.xml文件中定义的内容校验提交的数据。

Workflow Interceptor

workflow

调用Actionvalidate方法,一旦有错误返回,重新定位到INPUT画面

Parameter Filter Interceptor

N/A

从参数列表中删除不必要的参数

Profiling Interceptor

profiling

通过参数激活profile


转自http://www.open-open.com/lib/view/open1338339244354.html