之前写过一篇关于struts2的工作流程的博文因为本人能力又想而且第一次写可能写的比较乱、不好懂,希望大家可以原谅。这次打算再次深入学习struts2的核心机制,更细化struts2的理解。首先还是给出struts2的工作流程,这里个人选择了网上博文讲的比较正统的:
1、客户端请求一个HttpServletRequest的请求,如在浏览器中输入URL就是提交一个(HttpServletRequest)请求。
2、这个请求经过一系列的过滤器(Filter)如(ActionContextCleanUp、其他过滤器(SiteMesh等)、 FilterDispatcher)。注意:这里是有顺序的,先ActionContext CleanUp,再其他过滤器(Othter Filters、SiteMesh等),最后到FilterDispatcher。
FilterDispatcher是控制器的核心,就是MVC的Struts 2实现中控制层(Controller)的核心。
3、FilterDispatcher询问ActionMapper是否需要调用某个Action来处理这个(HttpServlet Request)请求,如果ActionMapper决定需要调用某个Action,FilterDispatcher则把请求的处理交给ActionProxy
4、ActionProxy通过Configuration Manager(struts.xml)询问框架的配置文件,找到需要调用的Action类。例如,用户注册示例将找到UserReg类
5、ActionProxy创建一个ActionInvocation实例,同时ActionInvocation通过代理模式调用Action。但在调用之前,ActionInvocation会根据配置加载Action相关的所有Interceptor(拦截器)。
6、一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果result
7、最后通过HTTPServletResponse返回客户端一个响应。
需要注意的是:
1、调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用
2、Struts 2的核心控制器是FilterDispatcher,有3个重要的方法:destroy()、doFilter()和Init(),可以在Struts 2的下载文件夹中找到源代码,执行顺序是:init()---- >doFilter()-------->destroy()
上面就大概的讲解一下struts2的工作流程,下面就讲下struts2的核心:
Struts2与前台交互的具体实现:
1.Struts2中的OGNL表达式 :
它可以用于,在JSP页面,使用标签方便的访问各种对象的属性;
它可以用于,在Action中获取传递过来的页面中的参数(并进行类型转换);
它还可以用在struts2的配置文件中
2.Struts2是通过ValueStack来进行赋值与取值的:
ValueStack实际上就是对OGNL的封装,OGNL主要的功能就是赋值与取值。
当 Struts 2接收到一个.action的请求后,调用拦截器链中的拦截器,当调用完所有的拦截器后,最后会调用Action类的Action方法,在调用Action方法之前,会建立Action类 的对象实例,先将Action类的相应属性放到 ValueStack对象的顶层节点(ValueStack对象相当于一个栈)。只是所有的属性值都是默认的值,如String类型的属性值为 null,int类型的属性值为0等。最后通过基本的getters方法,能够访问到某个对象的其它关联对象,并将 ValueStack对象顶层节点中的属性值赋给Action类中相应的属性。
Struts2中拦截器的动态代理以及AOP编程:
下面直接在源码中讲解:
/* 当Action请求到来的时候,会由系统的代理生成一个Action的代理对象,由这个代理对象调用Action的execute()或指定的方法,并在struts.xml中查找与该Action对应的拦截器。
如果有对应的拦截器,就在Action的方法执行前(后)调用这些拦截器;如果没有对应的拦截器则执行Action的方法。其中系统对于拦截器的调用,是通过ActionInvocation来实现的。 */
if (interceptors.hasNext()) {
Interceptor interceptor=(Interceptor)interceptors.next();
resultCode = interceptor.intercept(this);
} else {
if (proxy.getConfig().getMethodName() == null) {
resultCode = getAction().execute();
} else {
resultCode = invokeAction(getAction(), proxy.getConfig());
}
}
public abstract class AroundInterceptor extends AbstractInterceptor {
/* (non-Javadoc)
* @see com.opensymphony.xwork2.interceptor.AbstractInterceptor#intercept(com.opensymphony.xwork2.ActionInvocation)
*/
//1. 如果拦截器堆栈中还有其他的Interceptor,那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。
//2. 如果拦截器堆栈中只有Action了,那么invocation.invoke()将调用Action执行。
@Override
public String intercept(ActionInvocation invocation) throws Exception {
String result = null;
before(invocation);
// 调用下一个拦截器,如果拦截器不存在,则执行Action
result = invocation.invoke();
after(invocation, result);
return result;
}
/* 以invocation.invoke()为界,将拦截器中的代码分成2个部分,在invocation.invoke()之前的代码,将会在Action之前被依次执行,而在invocation.invoke()之后的代码,将会在Action之后被逆序执行。
invocation.invoke()作为Action代码真正的拦截点,从而实现AOP */
public abstract void before(ActionInvocation invocation) throws Exception;
public abstract void after(ActionInvocation invocation, String resultCode) throws Exception;
}
//DefaultActionInvocation中的invoke()方法:
/**
* @throws ConfigurationException If no result can be found with the returned code
*/
public String invoke() throws Exception {
String profileKey = "invoke: ";
try {
UtilTimerStack.push(profileKey);
if (executed) {
throw new IllegalStateException("Action has already executed");
}
//依次调用拦截器堆栈中的拦截器代码执行
if (interceptors.hasNext()) {
final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
UtilTimerStack.profile("interceptor: "+interceptor.getName(),
new UtilTimerStack.ProfilingBlock<String>() {
public String doProfiling() throws Exception {
// 将ActionInvocation作为参数,调用interceptor中的intercept方法执行
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
return null;
}
});
} else {
resultCode = invokeActionOnly();
}
// this is needed because the result will be executed, then control will return to the Interceptor, which will
// return above and flow through again
if (!executed) {
// 执行PreResultListener
if (preResultListeners != null) {
for (Iterator iterator = preResultListeners.iterator();iterator.hasNext();) {
PreResultListener listener = (PreResultListener) iterator.next();
String _profileKey="preResultListener: ";
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult(this, resultCode);
}
finally {
UtilTimerStack.pop(_profileKey);
}
}
}
// now execute the result, if we're supposed to
// action与interceptor执行完毕,执行Result
if (proxy.getExecuteResult()) {
executeResult();
}
executed = true;
}
return resultCode;
}
finally {
UtilTimerStack.pop(profileKey);
}
}
//Action层的4个不同的层次,在这个方法中都有体现,分别是:拦截器(Interceptor)、Action、PreResultListener和Result。在这个方法中,保证了这些层次的有序调用和执行。
/*
在intercept()方法又对ActionInvocation的invoke()方法进行递归调用,ActionInvocation循环嵌套在intercept()中,一直到语句result=invocation.invoke()执行结束。
这样,Interceptor又会按照刚开始执行的逆向顺序依次执行结束。
一个有序链表,通过递归调用,变成了一个堆栈执行过程,将一段有序执行的代码变成了2段执行顺序完全相反的代码过程,从而巧妙地实现了AOP。
*/
/*
拦截器与过滤器的区别:
1)拦截器是基于JAVA反射机制的,而过滤器是基于函数回调的。
2)过滤器依赖于Servlet容器,而拦截器不依赖于Servlet容器
3)拦截器只能对Action请求起作用,而过滤器可以对几乎所有的请求起作用。
4)拦截器可以访问Action上下文、值栈里的对象,而过滤器不能
5)在Action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
*/
因为上面的Interceptor的源码无法确切的体会到动态代理AOP机制,下面本人模拟Struts2的动态代理机制实现拦截器的AOP编程:
package interceptor;
//接口类
public interface Dog {
public void info();
public void run();
}
package interceptor;
//接口实现类
public class DogImpl implements Dog{
@Override
public void info() {
System.out.println("one dog...");
}
@Override
public void run() {
System.out.println("can run...");
}
}
package interceptor;
//定义的拦截器
public class DogInterceptor {
//第一个拦截方法
public void method1(){
System.out.println("first interceptor...");
}
//第二个拦截方法
public void method2(){
System.out.println("second interceptor...");
}
}
package interceptor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//实现动态代理的核心类
public class ProxyHandler implements InvocationHandler{
//代理的目标对象
private Object target;
//通过构造函数进行赋值
public ProxyHandler(Object target){
this.target=target;
}
//拦截器对象
DogInterceptor dogInterceptor=new DogInterceptor();
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
//根据方法名调用不同的拦截器
if(method.getName().equals("info")){
//before,第一个拦截器
dogInterceptor.method1();
//核心方法method.invoke(目标对象,args)
result=(Object) method.invoke(target, args);
//after,第二个拦截器
dogInterceptor.method2();
//可以明显看出就是AoP
}else{
//其他方法直接执行action
result=(Object) method.invoke(target, args);
}
//返回结果
return result;
}
}
package interceptor;
import java.lang.reflect.Proxy;
public class TestDog {
public static void main(String[] args){
//动态代理必须是接口的实现类
DogImpl targetobject=new DogImpl();
Dog proxy=(Dog) Proxy.newProxyInstance(Dog.class.getClassLoader(), new Class[] {Dog.class}, new ProxyHandler(targetobject));
proxy.info();
proxy.run();
}
}
输出结果:
first interceptor...
one dog...
second interceptor...
can run...
上述若有不对,欢迎各位指出,一起交流学习!