本文主要是介绍自己实现Struts2(四)实现ActionInvocation,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
上一章自己实现Struts2(三)实现ActionContext我已经实现好了Struts2的数据中心ActionContext,现在就要来实现一下action和拦截器的调用者ActionInvocation
再把Struts2框架流程图贴上来
大家可以发现拦截器链和action都是通过ActionInvocation来调用的,要实现这个功能,就必须准备好拦截器链和要被调用的action实例以及该action对应的配置信息(要通过配置信息知道调用什么方法),下面就来实现一下。
#ActionInvocation类成员变量介绍
现在我就来创建一个ActionInvocation
类,当然了,在Struts2中ActionInvocation是个接口,不过接口是为了方便扩展,我又没打算扩展,就直接定义类了。
package edu.jyu.invocation;import java.util.Iterator;import edu.jyu.config.ActionConfig;
import edu.jyu.context.ActionContext;
import edu.jyu.interceptor.Interceptor;/*** 拦截器链和action的调用类* * @author Jason*/
public class ActionInvocation {// 拦截器链private Iterator<Interceptor> interceptors;// 即将要被调用的action实例private Object action;// action配置信息private ActionConfig config;// 数据中心ActionContextprivate ActionContext invocationContext;}
其中Interceptor可以用Struts2自带的Interceptor
接口,不过在这里我自己写了一个,没什么差别的
package edu.jyu.interceptor;import edu.jyu.invocation.ActionInvocation;/*** 拦截器接口
* @author Jason*/
public interface Interceptor {/*** 执行拦截器初始化工作*/public void init();/*** 拦截功能,在请求前或请求后执行一些处理* @param invocation* @return */public String intercept(ActionInvocation invocation);/*** 让拦截器做一些释放资源工作*/public void destory();
}
可以看到上面的ActionInvocation类定义了四个成员变量,现在我就简单介绍一下这个几个变量
- interceptors:很明显这就是拦截器链了,存放着需要执行的拦截器,用
Iterator
类型是为了在后面调用的时候方便取出来。 - action:要调用的action实例。
- config:要调用的action实例对应的配置信息,要根据配置信息去调用action的方法。
- invocationContext:本次请求的数据中心,为action实例准备好。
下面就要来做一下准备工作了,把这几个数据都准备好。
#准备工作
数据准备工作放在构造器中,代码如下
/*** 准备各种需要的数据* * @param interceptorClassNames* 存放着拦截器链每个拦截器的全限定类名* @param config* 需要调用的action的配置信息* @param request* @param response*/
public ActionInvocation(List<String> interceptorClassNames, ActionConfig config, HttpServletRequest request,HttpServletResponse response) {// 准备Interceptor链if (interceptorClassNames != null && interceptorClassNames.size() > 0) {List<Interceptor> list = new ArrayList<Interceptor>();for (String className : interceptorClassNames) {try {Interceptor interceptor = (Interceptor) Class.forName(className).newInstance();interceptor.init();list.add(interceptor);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("创建Interceptor失败:" + className);}}interceptors = list.iterator();}// 准备action实例this.config = config;try {action = Class.forName(config.getClassName()).newInstance();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("创建Action失败:" + config.getClassName());}// 准备数据中心ActionContextinvocationContext = new ActionContext(request, response, action);
}
现在就来介绍一下准备工作。
一、准备拦截器链:构造方法会接受一个集合,里面存放着全部需要调用的拦截器的全限定类名,根据拦截器的全限定类名反射生成对应的实例,执行拦截器的初始化方法init
然后添加到另外一个集合中,最后调用interceptors = list.iterator();
赋值给interceptors,至此拦截器链就准备完毕了。
二、准备action实例:构造方法会接受一个ActionConfig
对象,这个对象存放的就是需要调用的action实例的配置信息,根据配置信息反射生成action实例。
三、准备ActionContext:这个没什么好讲的,直接new一个ActionContext对象将request、response和 action实例传进去,其中request和response对象是通过ActionInvocation的构造方法传进来的。
数据准备完成后就要开始调用了
#调用拦截器链和action
根据Struts2的框架流程图可以很清楚地看到,在调用action之前会先调用一系列的拦截器,在调用完action之后会逆序调用拦截器(其实就是执行Interceptor中intercept方法中的invocation.invoke()方法之后的代码),就是一个递归嘛,如果你会回溯法,对这个理解起来毫无压力。
不过需要注意的是,有可能拦截器直接返回一个字符串作为结果,这样action就不会被调用到了。
那么思路就是这样的:
-
如果拦截器链中还有其他的Interceptor,并且未被拦截器拦截(即未返回一个结果串),那么久调用下一个拦截器的拦截方法。
-
如果拦截器链中没有下一个拦截器了,那么根据action配置信息即
config
调用action实例的处理方法。 -
最后将结果串返回。
代码实现:
/*** 调用拦截器链和action处理方法* @param invocation * @return*/
public String invoke(ActionInvocation invocation) {// 结果串String result = null;// 判断拦截器链是否还有下一个拦截器或者未被拦截器拦截(result不等于null的话说明已经有拦截器直接返回结果串了)if (interceptors!=null && interceptors.hasNext() && result==null) {// 有下一个拦截器,调用下一个拦截器的拦截方法Interceptor next = interceptors.next();result = next.intercept(invocation);} else {// 没有下一个拦截器,调用action实例的处理方法// 获取处理的方法名String methodName = config.getMethod();try {Method method = action.getClass().getMethod(methodName);result = (String) method.invoke(action);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("action方法调用失败:" + methodName);}}return result;
}
拦截器链和action的整个调用流程就是这样子的了。
#获取ActionContext
在Struts2中ActionInvocation类有个方法ActionContext getInvocationContext()
会返回一个ActionContext对象,其实这个对象就是我们上面定义的invocationContext
,为action实例的调用而准备的,我们也可以提供获取它的方法。
public ActionContext getInvocationContext() {return invocationContext;
}
到了这里,整个ActionInvocation就完成了
ActionInvocation类完整代码:
package edu.jyu.invocation;import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import edu.jyu.config.ActionConfig;
import edu.jyu.context.ActionContext;
import edu.jyu.interceptor.Interceptor;/*** 拦截器链和action的调用类* * @author Jason*/
public class ActionInvocation {// 拦截器链private Iterator<Interceptor> interceptors;// 即将要被调用的action实例private Object action;// action配置信息private ActionConfig config;// 数据中心ActionContextprivate ActionContext invocationContext;/*** 准备各种需要的数据* * @param interceptorClassNames* 存放着拦截器链每个拦截器的全限定类名* @param config* 需要调用的action的配置信息* @param request* @param response*/public ActionInvocation(List<String> interceptorClassNames, ActionConfig config, HttpServletRequest request,HttpServletResponse response) {// 准备Interceptor链if (interceptorClassNames != null && interceptorClassNames.size() > 0) {List<Interceptor> list = new ArrayList<Interceptor>();for (String className : interceptorClassNames) {try {Interceptor interceptor = (Interceptor) Class.forName(className).newInstance();interceptor.init();list.add(interceptor);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("创建Interceptor失败:" + className);}}interceptors = list.iterator();}// 准备action实例this.config = config;try {action = Class.forName(config.getClassName()).newInstance();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("创建Action失败:" + config.getClassName());}// 准备数据中心ActionContextinvocationContext = new ActionContext(request, response, action);}/*** 调用拦截器链和action处理方法* @param invocation * @return*/public String invoke(ActionInvocation invocation) {// 结果串String result = null;// 判断拦截器链是否还有下一个拦截器或者未被拦截器拦截(result不等于null的话说明已经有拦截器直接返回结果串了)if (interceptors!=null && interceptors.hasNext() && result==null) {// 有下一个拦截器,调用下一个拦截器的拦截方法Interceptor next = interceptors.next();result = next.intercept(invocation);} else {// 没有下一个拦截器,调用action实例的处理方法// 获取处理的方法名String methodName = config.getMethod();try {Method method = action.getClass().getMethod(methodName);result = (String) method.invoke(action);} catch (Exception e) {e.printStackTrace();throw new RuntimeException("action方法调用失败:" + methodName);}}return result;}public ActionContext getInvocationContext() {return invocationContext;}
}
好了,ActionInvocation大功告成,项目已经上传到Github上
https://github.com/HuangFromJYU/JStruts2
如果大家有什么问题或者发现什么错误可以发邮件到jasonwong_hjj@qq.com,共同学习共同进步
这篇关于自己实现Struts2(四)实现ActionInvocation的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!