Struts2源码初探

             主要是对最新版本Struts2.3.1进行研究,之前从网上搜了一些文章,不过好些都是以前版本的,对比了一下最新版本的源码,最新版本对之前版本进行了重构,对比别人以前版本的文章还是能读懂的,现在让我们来看一下Struts2.3.1的源码。

先看一个从网上copy的struts2的体系结构图:

这图应该是以前版本的,目前struts2的核心控制器是StrutsPrepareAndExecuteFilter,从客户端发来的请求首先经过一系列的过滤器,这里我们可以配置一个ActionContextCleanUp的可选过滤器,它对于struts2和其他框架的继承很有帮助比如:SiteMesh plugin,最后核心控制器StrutsPrepareAndExecuteFilter被调用,我们来看一下核心控制器被调用后都做了什么:

StrutsPrepareAndExecuteFilter的init方法:

public void init(FilterConfig filterConfig) throws ServletException {
        InitOperations init = new InitOperations();
        try {
            FilterHostConfig config = new FilterHostConfig(filterConfig);
            init.initLogging(config);
	//创建dispacher,并将初始化信息传入对象中,并执行dispatcher的init方法
            Dispatcher dispatcher = init.initDispatcher(config);

            init.initStaticContentLoader(config, dispatcher);

            prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
            execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
			this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

            postInit(dispatcher, filterConfig);
        } finally {
            init.cleanup();
        }

    }

dispatcher的init方法是读取一些配置文件,我们进入到init方法中:

public void init() {

    	if (configurationManager == null) {
    		configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
    	}

        try {
            init_FileManager();
            init_DefaultProperties(); // [1]读取properties配置文件
            init_TraditionalXmlConfigurations(); // [2]读取Struts-default.xml和struts.xml文件
            init_LegacyStrutsProperties(); // [3]
            init_CustomConfigurationProviders(); // [5]
            init_FilterInitParameters() ; // [6]
            init_AliasStandardObjects() ; // [7]

            Container container = init_PreloadConfiguration();
            container.inject(this);
            init_CheckWebLogicWorkaround(container);

            if (!dispatcherListeners.isEmpty()) {
                for (DispatcherListener l : dispatcherListeners) {
                    l.dispatcherInitialized(this);
                }
            }
        } catch (Exception ex) {
            if (LOG.isErrorEnabled())
                LOG.error("Dispatcher initialization failed", ex);
            throw new StrutsException(ex);
        }
    }


客户端每发送一次请求,就会调用StrutsPrepareAndExecute的doFilter方法,我们用myeclipse的debug模式看一下处理请求的大致流程:

 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
		
       //将request、response分别转换为
        //HttpServletRequest、HttpServletResponse类型
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {
	 //设置编码格式和语言
            prepare.setEncodingAndLocale(request, response);
	 //创建ActionContext对象
            prepare.createActionContext(request, response);
            prepare.assignDispatcherToThread();
			if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
				chain.doFilter(request, response);
			} else {
				//根据不同的contentType使用不同的Request封装
				request = prepare.wrapRequest(request);
				//findActionMapping中通过ActionMapper创建新的ActionMapping对象
				//创建的过程包括对uri的解析,并将解析后的namespace和name、method等设置到mapping中
				ActionMapping mapping = prepare.findActionMapping(request, response, true);
				if (mapping == null) {
					boolean handled = execute.executeStaticResourceRequest(request, response);
					if (!handled) {
						chain.doFilter(request, response);
					}
				} else {
					//正式调用action
					execute.executeAction(request, response, mapping);
				}
			}
        } finally {
            prepare.cleanupRequest(request);
        }
    }


我们进入executeAction方法中:

/**
     * Executes an action
     * @throws ServletException
     */
    public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
        dispatcher.serviceAction(request, response, servletContext, mapping);
    }


它调用了dispatcher的serviceAction方法,我们接着进入:

 public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
                              ActionMapping mapping) throws ServletException {

				.............省略代码...........

        String timerKey = "Handling request from Dispatcher";
        try {
            UtilTimerStack.push(timerKey);
			//得到namespace、name、method
            String namespace = mapping.getNamespace();
            String name = mapping.getName();
            String method = mapping.getMethod();

            Configuration config = configurationManager.getConfiguration();

			//创建Action的代理对象ActionProxy对象,通过它完成action的调用
            ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
                    namespace, name, method, extraContext, true, false);

            request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

            // if the ActionMapping says to go straight to a result, do it!
            if (mapping.getResult() != null) {
                Result result = mapping.getResult();
                result.execute(proxy.getInvocation());
            } else {
                proxy.execute();
            }

           .............省略代码............
    }


我们来看一下ActionProxy对象的创建过程,进入到createActionProxy方法中:

 public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext);

看到这傻眼了吧,还好之前学了设计模式,典型的Template Method模式,我们去它的子类找实现,发现调用的DefaultActionProxyFactory中的方法:

 public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {
        //创建ActionInvocation对象
        ActionInvocation inv = new DefaultActionInvocation(extraContext, true);
        container.inject(inv);
        return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
    }

我们接着进入createActionProxy方法中:

 public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {

        DefaultActionProxy proxy = new DefaultActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
        container.inject(proxy);
        proxy.prepare();
        return proxy;
    }

接着调用了DefaultActionProxy的prepare方法,进入:

 @Override
    protected void prepare() {
        super.prepare();
    }

调用基类的prepare方法:

 protected void prepare() {
        String profileKey = "create DefaultActionProxy: ";
        try {
            UtilTimerStack.push(profileKey);
            config = configuration.getRuntimeConfiguration().getActionConfig(namespace, actionName);

            if (config == null && unknownHandlerManager.hasUnknownHandlers()) {
                config = unknownHandlerManager.handleUnknownAction(namespace, actionName);
            }
            if (config == null) {
                throw new ConfigurationException(getErrorMessage());
            }

            resolveMethod();

            if (!config.isAllowedMethod(method)) {
                throw new ConfigurationException("Invalid method: " + method + " for action " + actionName);
            }
			//调用invocation的init方法创建action
            invocation.init(this);

        } finally {
            UtilTimerStack.pop(profileKey);
        }
    }

进入到init方法中:

public void init(ActionProxy proxy) {
        this.proxy = proxy;
        Map<String, Object> contextMap = createContextMap();

        // Setting this so that other classes, like object factories, can use the ActionProxy and other
        // contextual information to operate
        ActionContext actionContext = ActionContext.getContext();

        if (actionContext != null) {
            actionContext.setActionInvocation(this);
        }
		//创建action
        createAction(contextMap);

        if (pushAction) {
            stack.push(action);
            contextMap.put("action", action);
        }

        invocationContext = new ActionContext(contextMap);
        invocationContext.setName(proxy.getActionName());

        // get a new List so we don't get problems with the iterator if someone changes the list
		//将过滤器放到list集合中
        List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
        interceptors = interceptorList.iterator();
    }


我们接着看invocation是如何创建action的,进入createAction方法中:

 protected void createAction(Map<String, Object> contextMap) {
        // load action
        String timerKey = "actionCreate: " + proxy.getActionName();
        try {
            UtilTimerStack.push(timerKey);
			 //这儿默认建立Action是StrutsObjectFactory,实际中我使用的时候都是使用Spring创建的Action,这个时候使用的是SpringObjectFactory
            action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);
        } catch (InstantiationException e) {
            throw new XWorkException("Unable to intantiate Action!", e, proxy.getConfig());
        } 
		...........省略代码..........
    }


到这我们应该就能确定action已经创建完毕,进入buildAction内部是通过反射机制创建的action,这里就不再详细说明,我们接着回到dispatcher的serviceAction方法中,创建完ActionProxy对象后,通过debug模式发现调用了ActionProxy的execute方法,进入:调用了StrutsActionProxy的execute方法,方法中又调用了DefaultActionInvocation的invoke方法,进入Invoke方法中:

 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 = interceptors.next();
                String interceptorMsg = "interceptor: " + interceptor.getName();
                UtilTimerStack.push(interceptorMsg);
                try {
                                resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
                            }
                finally {
                    UtilTimerStack.pop(interceptorMsg);
                }
            } else {
				//拦截器执行完后执行action相应的方法
                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) {
				//在结果返回之前调用preResultListeners
                if (preResultListeners != null) {
                    for (Object preResultListener : preResultListeners) {
                        PreResultListener listener = (PreResultListener) preResultListener;

                        String _profileKey = "preResultListener: ";
                        try {
                            UtilTimerStack.push(_profileKey);
                            listener.beforeResult(this, resultCode);
                        }
                        finally {
                            UtilTimerStack.pop(_profileKey);
                        }
                    }
                }

                // now execute the result, if we're supposed to
                if (proxy.getExecuteResult()) {
					//对返回的结果做出响应
                    executeResult();
                }

                executed = true;
            }

            return resultCode;
        }
        finally {
            UtilTimerStack.pop(profileKey);
        }
    }


进入到invokeActionOnly方法中发现其调用了DefaultActionInvocation的invokeAction方法:

 protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
			........省略代码........

            if (!methodCalled) {
				//通过反射调用action中的方法返回字符串
                methodResult = method.invoke(action, EMPTY_OBJECT_ARRAY);
            }
			//返回一个字符串
            return saveResult(actionConfig, methodResult);
        }
		...............省略代码..........
    }


结果返回我我们接着看上面DefaultActionInvocation的invoke方法中,result返回后调用executeResult方法:

 private void executeResult() throws Exception {
        result = createResult();

        String timerKey = "executeResult: " + getResultCode();
        try {
            UtilTimerStack.push(timerKey);
            if (result != null) {
				//对结果进行处理,跳转到相应的页面
                result.execute(this);
            } else if (resultCode != null && !Action.NONE.equals(resultCode)) {
                throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()
                        + " and result " + getResultCode(), proxy.getConfig());
            } else {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());
                }
            }
        } finally {
            UtilTimerStack.pop(timerKey);
        }
    }

再调用完result.execute(this)方法后还要以倒叙的顺序执行一遍拦截器。Ok,一个Struts2的请求流程基本上就结束了。等以后仔细研究后再补充吧





 



 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值