struts2的核心机制学习

    之前写过一篇关于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...

上述若有不对,欢迎各位指出,一起交流学习!




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值