beauty_beast

上善若水 厚德载物

学习设计模式之proxy模式

Posted on 2005-08-19 16:58 柳随风 阅读(927) 评论(0)  编辑  收藏 所属分类: java基础

前言: 本文只是本人的学习总结,目的希望能和大家一起交流分享,顺便备忘,如有不正确的地方,欢迎指正。本文可能需要你对webwork框架有一定的了解。

 

我们在开发中Proxy模式是经常用到的,代理主要用来对访问的资源进行权限控制以及监控的目的,如果我们在开发系统需要对访问的对象进行控制和监控的话,proxy模式是很有用途的。

举些例子:

我们开发一个应用系统时,用户请求任何页面都要经过权限控制,最早开发的时候我们常常封装一个权限验证方法,然后在每个jsp或者对应的servlet中增加相关代码,但是用户对权限的需求往往是多变的,这样一旦权限验证方法变化(参数变化,增加方法),如果开发的系统很庞大的话,有可能你就需要修改几百个jsp页面或者servlet代码。

还有我们常需要判断session是否过期,如果过期就要重新登陆系统,如果每个页面或者servlet都要加判断代码,那也是件比较痛苦的事情。

如果我们采用代理模式,增加Proxy对象,每次用户请求必须通过proxy对象处理,由它专门处理相关权限控制,一旦权限需求变化了,只需要修改Proxy对象相关的实现方法。

Proxy模式不仅仅用于上述场景,还可以在其他方面应用。

 

我们可以研究研究webwork的源代码,看看它是如何设计的。

 

webwork开发框架目前是比较流行的web开发框架之一,最近我的开发项目就采用了该框架,它相比struts有很多优点(晚出来的再没优点也不行啊,呵呵,关于其缺点也有,有时间再说),

主要如下:

1、    易单元测试;

2、    线程安全;

3、    允许使用截取器模块化前/后处理. 拦截器可以通过配置动态添加, 两者之间没有任何耦合;

4、    WebWork 2使用Ognl, 强大的表达式语言, 也可以访问值栈. Ognl对集合和索引属性的支持非常强大。

其中优点3的实现和proxy模式是非常相关的,下面就讲讲webwork如何采用Proxy模式实现其优点3的。

 

首先我们看看webwork的核心类ServletDispatcher的请求处理代码:

public void serviceAction(
HttpServletRequest request, HttpServletResponse response, 
String 
namespace, String actionName, 
Map requestMap, Map parameterMap, 
Map sessionMap, Map applicationMap) 
{
HashMap extraContext 
= createContextMap(requestMap, parameterMap, sessionMap, applicationMap, request, response, getServletConfig());
extraContext.put(SERVLET_DISPATCHER, 
this);
try {
    ActionProxy proxy 
=   ActionProxyFactory.getFactory).
createActionProxy(
namespace, actionName, extraContext);
   request.setAttribute(
"webwork.valueStack", proxy.getInvocation().getStack());
   proxy.execute();
}

catch (ConfigurationException e) {
   log.error(
"Could not find action", e);
   sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);
       }

catch (Exception e) {
   log.error(
"Could not execute action", e);
   sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,e);
}

}


.可以看到整个对请求的处理非常简练:通过工厂方法获取一个ActionProxy 实例,执行ActionProxy实例的execute()方法,所有请求都需要通过该方法处理。

ActionProxyFactory.getFactory().createActionProxy(namespace, actionName, extraContext);

这段代码调用过程我简单描述一下:

    首先ActionProxyFactory.getFactory().获取到一个DefaultActionProxyFactory实例,然后该工厂实例调用createActionProxy(相关参数)方法创建一个DefaultActionProxy示例。
 

下面我们看看这个DefaultActionProxy究竟是如何处理的:

首先它会根据相关信息获取当前Action配置对象,从中可以知道当前Action中配置了那些拦截器、Result等等配置信息,具体可以查看ActionConfig对象,然后创建一个调用对象DefaultActionInvocation实例(也是通过工厂方法),该实例调用invoke()方法完成该action配置的拦截器的拦截方法以及actionexecute()方法或action自定义的method的执行。

public String invoke() throws Exception {
        
if (executed) {
            
throw new IllegalStateException("Action has already executed");
        }

        
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());
            }

        }

        
// 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) {
            
if (preResultListeners != null{
                
for (Iterator iterator = preResultListeners.iterator();
                        iterator.hasNext();) 
{
                    PreResultListener listener 
= (PreResultListener) iterator.next();
                    listener.beforeResult(
this, resultCode);
                }

            }


            
// now execute the result, if we're supposed to
            if (proxy.getExecuteResult()) {
                executeResult();
            }

            executed 
= true;
        }

        
return resultCode;
    }

而一般拦截器对象都是AroundInterceptor的子类,在AroundInterceptor类中的拦截方法如下:

   public String intercept(ActionInvocation invocation) throws Exception {
        String result 
= null;
        before(invocation);
        result 
= invocation.invoke();
        after(invocation, result);
        
return result;
    }

 

注意该调用对象的invoke方法比较有意思,它采用的是遍历调用的方式,每个Action一般都有多个拦截器,每个拦截器执行完毕后再回调该调用对象的invoke方法,有点像链式,如果中间有自定义拦截器有发现异常,不要再执行下去,直接返回Result相关字符串,中断之后的拦截器以及Action不再执行,正常情况下链尾是调用对应Action实例的execute()方法,获取Result相关字符串后,根据字符串值获取相关Result实例,执行Result实例中excute()方法派发或者重导向到相关视图(jspvm等等),一旦链尾处理过请求后,链中的其他节点就不需要再派发。只需继续执行拦截器中的after()方法(如果有的话)的执行,webwork采用这样的方式实现主要是为了满足action后处理功能的需要(有点跑题了,变成webwork框架源码分析)

题外话:从整个调用过程我们可以发现: Webwork框架的核心功能实际上都是在Xwork框架中实现的,Webwork实际上只是XworkB/S系统上的应用。

 

结束总结:

1、我们在开发时,如果要对访问的对象进行统一预处理、控制、监控管理时可以采用Proxy模式。

2Proxy模式往往和Factory模式一起使用。个人理解是因为考虑系统的扩展性、通用性,有可能有不同的类型的Proxy以及调用,根据不同的应用场景,可以采用不同的工厂创建。

3、如果运用的不是很恰当的话,会造成Proxy的实现很庞大,并且和相关对象耦合过高,而webwork采用配置每个action对应的拦截器这种设计就非常好,耦合也比较低,实际上它变相的实现了每个对象采用不同的Proxy,个人感觉其这方面的设计很不错,可以借鉴。






只有注册用户登录后才能发表评论。


网站导航: