拦截器实现机制
一、回忆“java反射与动态代理二.txt”,因为它的底层原理是java动态代理
二、拦截器类实现机理就是将如下java动态代理类DynamicSubject 中“before”“after”提取出来形成一个类。
即在 真正使用目标类方法前和方法类后需要做的事或叫调用的函数独立出来,形成一个类,就像此类打印“before calling"或打印“after calling”两个方法单独独立出来一个类,然后是通过类的方法去调用这两个方法,其实拦截器类本省没有做什么,无非就是定义了真正的在处理某个实际类之前需要做什么事情,而实现主要还是通过动态代理去实现的。
三、拦截器实现原理
通过以下代码来阐述
1、TargetInterface接口(因为java实现动态代理需要面向接口)
package com.interceptor; public interface TargetInterface { public void doSomething(); }
2、Target.java
package com.interceptor; public class Target implements TargetInterface { public void doSomething() { System.out.println("do something"); } }
3、Interceptor.java 拦截器类,其实拦截器类本身是一个很普通的类,他和上面的目标类也是没有耦合关系的,通过下面的处理器类MyHandler.java类会将它们耦合在一起
package com.interceptor; public class Interceptor { public void before() { System.out.println("before"); } public void after() { System.out.println("after"); } }
4、MyHandler.java类,该类实现了InvocationHandler接口,覆写了invoke方法。
package com.interceptor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyHandler implements InvocationHandler { private Object object; private Interceptor interceptor = new Interceptor(); public void setObject(Object object) { this.object = object; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; interceptor.before(); result = method.invoke(object, args); interceptor.after(); return result; } }
5、Myproxy.java该类 的作用是根据Proxy的静态方法生成代理类,返回
package com.interceptor; import java.lang.reflect.Proxy; public class MyProxy { public Object getProxy(Object object) { MyHandler myHandler = new MyHandler(); myHandler.setObject(object); return Proxy.newProxyInstance(Target.class.getClassLoader(), object .getClass().getInterfaces(), myHandler); } }
6、客户端Client.java
package com.interceptor; public class Client { public static void main(String[] args) { TargetInterface target = new Target(); MyProxy myProxy = new MyProxy(); TargetInterface proxy = (TargetInterface)myProxy.getProxy(target); proxy.doSomething(); } }
7、执行结果
before do something after
四、拦截器的使用
1、类MyInterceptor
package com.test.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.Interceptor; public class MyInterceptor implements Interceptor//必须继承这个接口,覆写下面三个//方法 { private String hello; public String getHello() { return hello; } public void setHello(String hello) { this.hello = hello; } public void destroy() { System.out.println("destroy"); } public void init() { System.out.println("init"); System.out.println(hello); } public String intercept(ActionInvocation invocation) throws Exception { System.out.println("intercept"); String result = invocation.invoke();//当有拦截器链的时后,一直传递下去一个个拦截下去 System.out.println("finish"); return result; } }
2、在struts.xml文件中配置拦截器
<interceptor name="myInterceptor" class="com.test.interceptor.MyInterceptor"> <!--此处的参数"hello"值为world可以在拦截器使用类中被读取或叫动态加载,如上面MyInterceptor --> <param name="hello">world</param> </interceptor>
3、在struts.xml文件中使用拦截器
<action name="register" class="com.test.action.RegisterAction" method="test"> <result name="success">/success.jsp</result> <result name="input">/register2.jsp</result> <interceptor-ref name="auth"> <param name="hello">world2222</param><!--此处的参数"hello"值为world可以被替换掉--> </interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </action>
说明:如果对于某一个action你增加了一个拦截器配置,那么你需要再显示地引用默认拦截器。<interceptor-ref
name="defaultStack"></interceptor-ref>
拦截器的执行顺序:先配置的先执行,但退出的时候,后配置的先执行。
即在struts.xml类中,对某一个action。如果你没有增加任何拦截器,那么Action会去引用默认拦截器,会默认加载。(每一个action
会有一个而且只能有一个的默认的拦截器
如果对于某一个action你增加了一个拦截器配置,那么你需要再显示地声明默认拦截器。
拦截器的执行顺序:先配置的先执行,但退出的时候,后配置的先执行。
五、拦截器栈
拦截器栈可以有多个拦截器组成
也可以由别的拦截器栈和拦截器等组成
默认的拦截器栈只有一个,可以通过struts.xml中设置<default-interceptor-ref name="defaultStack"/>,defaultStack系统指定的
默认的拦截器栈!默认的拦截器栈可以修改的。例如修改为myDefaultStack等
拦截器栈在struts.xml中的使用举例
<interceptors> <interceptor name="myInterceptor" class="com.test.interceptor.MyInterceptor"> <param name="hello">world</param> </interceptor> <interceptor name="myInterceptor2" class="com.test.interceptor.MyInterceptor2"> </interceptor> <interceptor name="myInterceptor3" class="com.test.interceptor.MyInterceptor3"> </interceptor> <interceptor name="auth" class="com.test.interceptor.AuthInterceptor"> </interceptor> <interceptor-stack name="myStack"> <interceptor-ref name="myInterceptor"></interceptor-ref> <interceptor-ref name="myInterceptor2"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </interceptor-stack> </interceptors>
六、AbstractInterceptor已经实现拦截器的init方法、和destroy()方法
所以直接继承之它会比较简单。
如:MyInterceptor2.java
package com.test.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class MyInterceptor2 extends AbstractInterceptor { @Override public String intercept(ActionInvocation invocation) throws Exception { System.out.println("intercept2"); String result = invocation.invoke(); System.out.println("finish2"); return result; } }
七、选择性拦截
1、拦截某个方法时,可以在struts.xml中定义
如:
<action name="register" class="com.test.action.RegisterAction" method="test"> <result name="success">/success.jsp</result> <result name="input">/register2.jsp</result> <interceptor-ref name="auth"></interceptor-ref><!--对执行test方法时拦截--> <interceptor-ref name="defaultStack"></interceptor-ref> </action>
2、方法过滤拦截器可以直接继承MethodFilterInterceptor(继承之AbstractInterceptor)
1)拦截器类MyInterceptor3
package com.test.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; public class MyInterceptor3 extends MethodFilterInterceptor { @Override public void init() { System.out.println("init3"); } @Override protected String doIntercept(ActionInvocation invocation) throws Exception { System.out.println("my interceptor3"); String result = invocation.invoke(); System.out.println("after my interceptor3 finished"); return result; } }
2)在struts.xml中定义
<interceptor name="myInterceptor3" class="com.test.interceptor.MyInterceptor3"> </interceptor> <action name="register" class="com.test.action.RegisterAction" method="test"> <result name="success">/success.jsp</result> <result name="input">/register2.jsp</result> <interceptor-ref name="myInterceptor3"> <param name="excludeMethods">test,execute</param> <!-- <param name="includeMethods">test</param> --> </interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </action>
八、注册监听器
1、MyListener.java监听器类
package com.test.listener; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.PreResultListener; public class MyListener implements PreResultListener { public void beforeResult(ActionInvocation invocation, String resultCode) { System.out.println("result : " + resultCode); } }
2、MyInterceptor.java
package com.test.interceptor; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; import com.test.listener.MyListener; public class MyInterceptor3 extends MethodFilterInterceptor { @Override public void init() { System.out.println("init3"); } @Override protected String doIntercept(ActionInvocation invocation) throws Exception { invocation.addPreResultListener(new MyListener());//此处为注册监听器 System.out.println("my interceptor3"); String result = invocation.invoke(); System.out.println("after my interceptor3 finished"); return result; } }
执行结果
my interceptor3 validate(方法)。。。。。 result : input(即返回结果但把结果给客户端方法之前,会执行这个监听器类) after my interceptor3 finished
九、用户登录才能操作的例程
1、AuthInterceptor.java
package com.test.interceptor; import java.util.Map; import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class AuthInterceptor extends AbstractInterceptor { @Override @SuppressWarnings("unchecked") public String intercept(ActionInvocation invocation) throws Exception {//struts2已经把session从容器里脱离出来了,放在map中了,所以使用和测试都很方便。 Map map = invocation.getInvocationContext().getSession(); if(map.get("user") == null) { return Action.LOGIN; } else { return invocation.invoke(); } } }
2、改造LoginAction.java类的excute方法,即把用户放在session里
import java.util.Map; import com.opensymphony.xwork2.ActionContext; public String execute() throws Exception { if ("hello".equals(this.getUsername().trim()) && "world".equals(this.getPassword().trim())) { Map map = ActionContext.getContext().getSession(); map.put("user","valid"); return "success"; }
3、修改struts.xml
<interceptor name="auth" class="com.test.interceptor.AuthInterceptor"> </interceptor> <action name="register" class="com.test.action.RegisterAction" method="test"> <result name="success">/success.jsp</result> <interceptor-ref name="auth"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> </action> 还有因为大家不成功时都转到登录界面,所以可以配置全局的input,redirect属性值表示重定向,struts这里的默认值是dispatcher <groble-results> <result name="login" type="redirect">/login2.jsp</result> </groble-results>