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为我们提供了一定代理机制!
Java在java.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()之前和之后插入拦截的功能。
2.OK,上面讲的一个采用我们自定义拦截器的方式实现在目标拦截的功能,下面的我们看一下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中的
对于上面的拦截器,我们需要在struts.xml文件中如下配置
方式1:
world output.jsp input.jsp welcom
我们将一个拦截配置在point这个Action中,说明我们要使用这个拦截器来拦截这个Action,见红色的字体,拦截器配置中间我们还加了一个参数,struts2会自动将该参数的值加载到拦截器中对应属性的值。OK,这样配置好了,运行程序测试,发现结果数据是错误的。这是为什么呢?
前面说过Struts2会为每个Action应用一个默认的拦截器,这个拦截器是在struts-default.xml文件中配置的,而我们的struts.xml开关又出现这样的配置
说明我们的配置继承了struts-default.xml中的配置。
当我们如下配置文件中那样配置后,默认的配置就会被引用了,这是Struts2本身所有实现的,当我们为一个Action配置了拦截器时,默认的拦截器就会失效,但是Struts2本身的一些功能,比如说参数自动赋值又是依赖配置的默认拦截器实现,所有应用程序会出错。这时需要我们手动将默认的拦截器引用进来,再为这项Action加入默认拦截器:
另外要注意:如果拦截器声明时和引用时都配置了参数,那最引用时的参数配置是有效的。
比如:上面的配置在配置拦截器时给hello参数传一个”world”,但在下面action中使用拦截器时,又给参数hello配置了"welcome”值,最终使用的将是action使用时拦截器时配置的值。
方式2:
我们为简便,还可以定义一个拦截链,上面说过,拦截链和拦截器一样,所以我们也在
output.jsp
上面我们配置一个拦截链,但是我们并没有写在下面的action中,运行程序PointAction还是被拦截了。这是为什么呢?看上面有这样一句配置:
这句配置是定义了一个默认拦截链或拦截器,这个拦截就像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
// 需要拦截的方法名列表
protected Set
以上两个属性,一个是指定哪些方法需要拦截,另一个是指定哪些方法不需要拦截。在配置拦截器时需要配置这两个参数。
我们行定义一个方法拦截器,代码如下: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;
}
}
下面我们配置这个方法拦截器:
world execute,login logout
注意:同时指定拦截方法和排除方法时,拦截方法的级别高。
上面举的例子拦截器中东西都比较简单,真正在开发时候需要根据具体的业务来编写拦截器的内容!所以大家在实际项目中多多练习便会慢慢的掌握拦截器,另外Struts2中自带了的拦截器、拦截链(在struts-default.xml中),大家还是应该了解下的,具体如下:
拦截器 |
名字 |
说明 |
Alias Interceptor |
alias |
在不同请求之间将请求参数在不同名字件转换,请求内容不变 |
Chaining Interceptor |
chain |
让前一个Action的属性可以被后一个Action访问,现在和chain类型的result( |
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调用Action的setModel方法将其放入Action内部。 |
Parameters Interceptor |
params |
将请求中的参数设置到Action中去。 |
Prepare Interceptor |
prepare |
如果Acton实现了Preparable,则该拦截器调用Action类的prepare方法。 |
Scope Interceptor |
scope |
将Action状态存入session和application的简单方法。 |
Servlet Config Interceptor |
servletConfig |
提供访问HttpServletRequest和HttpServletResponse的方法,以Map的方式访问。 |
Static Parameters Interceptor |
staticParams |
从struts.xml文件中将 |
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 |
调用Action的validate方法,一旦有错误返回,重新定位到INPUT画面 |
Parameter Filter Interceptor |
N/A |
从参数列表中删除不必要的参数 |
Profiling Interceptor |
profiling |
通过参数激活profile |
转自http://www.open-open.com/lib/view/open1338339244354.html