拦截器是Struts2的核心内容之一,号称完成了Struts框架的70%的工作,它体现了一种AOP(面向切面编程)的设计哲学,它还体现了软件开发领域DRY(Don’t repeat yourself)原则。
Struts2中拦截器实际上也是一个类,它包含特殊的方法,能够拦截到要执行的方法,在这个方法执行之前或者之后插入其他功能,而且这些功能是自动完成的。个人理解,什么是拦截器呢,就像搞硬件的里面的中断器一样,拦截到正在执行的方法,强制在该方法前面插入一段代码,等待这段代码执行完毕,再执行拦截到的方法,然后还可以根据需要再次添加一段自动执行的方法。
它的优势在于:提供更高层次的解耦。目标代码不需要手动调用目标方法,均是由系统自动完成。它在struts框架中发挥的作用包括:将params拦截HTTP请求的参数解析出来,设置成Action属性,Servlet-config拦截器将HTTP请求的HttpServletRequst和HttpServletResponse传给Action;fileUpload拦截器负责解析需要求情参数的文件域等等,这些拦截器都是系统默认配置完成的,位于struts-defults.xml文件下!
<interceptors>
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="externalRef" class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/>
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="sessionAutowiring" class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="jsonValidation" class="org.apache.struts2.interceptor.validation.JSONValidationInterceptor" />
<interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
【拦截器实现原理】
我们先来用JDK动态代理(只能对实现了接口的实例动态生成代理)的方式来了解下拦截器的实现过程:
1.创建实例接口:
public interface Dog{
Public void info();
Public void run();
}
2.实例实现:
Public class DogImpl implements dog
{
Public void info(){
System.out.println("这是一只狗");
}
Poublic void run(){
System.out.println("奔跑迅速");
}
}
3. 创建拦截器类:
Public class DogIntorcepter{
Poublic void mathod1(){
System.out.println("拦截器方法一");
}
Public void method2(){
System.out.println("拦截器方法二");
}
}
Public class ProxyHandler implements InvocationHandler{
//需要被代理的目标对象
Private Object target;
//创建拦截器实例
DogIntercepter di=new DogInterceptor();
//执行目标对象方法时,invoke方法会自动调用
Public Object invoe(object proxy,Method method,object[] args) throws Exception{
Object result=null;
If(method.getName().equals("info")){
//如果调用了info方法,则先执行method1,然后执行info,最后执行method2
Di.method1();
Result=method.invoke(target,args);
Di.method2();
}else{
Result=method.invoke(target,args);
}
Return result;
}
Public void setTarget(Object o){
This.target=o;
}
}
5. 代理工厂类,根据目标对象和对应的拦截器生成新代理对象(包含了目标方法和拦截器方法组合)
Public class MyProxyFactory{
Public static Object getProxy(Object object){
//代理处理类
ProxyHandler handler=new ProxyHandler();
Handler.setTarget(object);
//第一个参数是创建动态代理的classLoader对象(
ClassLoader主要对类的请求提供服务,当JVM需要某类时,它根据名称向ClassLoader要求这个类,然后由ClassLoader返回这个类的class对象。
)
//第二个参数接口数组,代理该接口数组
//第三个代理包含的处理实例
Return Proxy.newProxyInstance(DogImpl.class.getClassLoader(),Object.getClass().getInterfaces(),handler);
}
}
主程序:
Public class TestDog{
Poublic static void main(String[] args){
Dog targetObject=new DogImpl();
Dog dog=null;
Object proxy=MyProxyFactory.getProxy(targetObject);
If(proxy instance of Dog){
Dog=(Dog)proxy;
}
//测试代理方法
Dog.info();
Dog.run();
}
}
根据上面的过程,可以分析,拦截器和实例都是两个普通的类,通过实现InvacationHandler接口,将代理的方法有可能包含实例本身和拦截器的方法,并赋予一定的执行顺序,并通过JVM创建出动态代理对象,执行代理对象的info()方法,实际上执行了method1,info()和method2()方法。
【拦截器配置与使用】
(1)自定义实现拦截器类,主要有两种方式,一是实现com.opensymphony.xwork2.interceptor.Interceptor接口,另一种则是继承AbstractInterceptor类,重写Interceptor方法
public class TheInterceptor1 implements Interceptor {
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
System.out.println("init setTest");
this.test = test;
}
//拦截器被销毁之前,主要用于销毁init()申请的资源
public void destroy() {
// TODO Auto-generated method stub
}
//拦截器被初始化后,执行拦截之前,系统回调该方法,执行性一次,用于一些一次性资源,例如数据库连接
public void init() {
System.out.println("init invoked");
System.out.println("test:"+this.test);
}
//用户需要的拦截动作
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("before");
System.out.println("interceptor1:"+invocation.getAction().getClass());
//在执行对应的Action方法之前,输出befor+拦截行为的类,之后输出after
String resultString=invocation.invoke();
System.out.println("after");
return resultString;
}
}
public class TheInterceptor2 extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("interceptor vefore...");
System.out.println("interceptor2:"+invocation.getAction().getClass());
String resultString =invocation.invoke();
System.out.println("interceptor after...");
return resultString;
}
}
如果两个拦截器都被使用的话,则是一种嵌套存在的形式,例如,loginAction的execute同时配置了TheInterceptor1和 TheInterceptor2,则输出的结果为:
before
TheInterceptor1:loginAction
before
TheInterceptor2:loginAction
LoginAction。execute的方法输出
interceptor after...
atter
(2)在配置文件Struts.xml中的配置:
<interceptors>
<interceptor name="theInterceptor1" class="org.whp.interceptor.TheInterceptor1">
<param name="test">whp</param>
</interceptor>
<interceptor name="theInterceptor2" class="org.whp.interceptor.TheInterceptor2">
</interceptor>
<interceptor name="theInterceptor3" class="org.whp.interceptor.TheInterceptor3">
</interceptor>
</interceptors>
<!-- 定义拦截器栈 -->
<intercepetor-stack name="myDefaultInterceptorStack">
<interceptor-ref name="loginInterceptor"></interceptor-ref>
<interceptor-ref name="defaultInterceptor"></interceptor-ref>
</intercepetor-stack>
Action中配置对应的拦截器:
<action name="action1" class="org.whp.mystruts2.Action1">
<result name="success" type="redirectAction">
<param name="actionName">action2</param>
<!-- <param name="username">${username}</param> -->
<param name="username">${username1}</param>
<param name="password">${password}</param>
<param name="usernameAndPassword">${usernameAndPassword}</param>
</result>
<interceptor-ref name="theInterceptor1"></interceptor-ref>
<interceptor-ref name="theInterceptor2"></interceptor-ref>
<interceptor-ref name="theInterceptor3">
<param name="includeMethods">execute,myExecute</param> <!-- 对execute方法进行拦截 -->
<!--<param name="excludeMethods">myExecute</param> --> <!-- 不对myExecute进行拦截 -->
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
对各个action通用的拦截器,可以设置默认引用:
<!-- 定义默认的拦截器,引用拦截器栈 -->
<default-interceptor-ref name="myDefaultInterceptorStack"></default-interceptor-ref>