zoukankan      html  css  js  c++  java
  • Struts2 架构图

    Struts2架构图 


            请求首先通过Filter chain,Filter主要包括ActionContextCleanUp,它主要清理当前线程的ActionContext和Dispatcher;FilterDispatcher主要通过AcionMapper来决定需要调用哪个Action。 
            ActionMapper取得了ActionMapping后,在Dispatcher的serviceAction方法里创建ActionProxy,ActionProxy创建ActionInvocation,然后ActionInvocation调用Interceptors,执行Action本身,创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。 


    Struts2部分类介绍 
    这部分从Struts2参考文档中翻译就可以了。 
    ActionMapper 
            ActionMapper其实是HttpServletRequest和Action调用请求的一个映射,它屏蔽了Action对于Request等java Servlet类的依赖。Struts2中它的默认实现类是DefaultActionMapper,ActionMapper很大的用处可以根据自己的需要来设计url格式,它自己也有Restful的实现,具体可以参考文档的docsactionmapper.html。 
    ActionProxy&ActionInvocation 
            Action的一个代理,由ActionProxyFactory创建,它本身不包括Action实例,默认实现DefaultActionProxy是由ActionInvocation持有Action实例。ActionProxy作用是如何取得Action,无论是本地还是远程。而ActionInvocation的作用是如何执行Action,拦截器的功能就是在ActionInvocation中实现的。 
    ConfigurationProvider&Configuration 
            ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其实现类XmlConfigurationProvider及其子类StrutsXmlConfigurationProvider来解析, 


    Struts2请求流程 
    1、客户端发送请求 
    2、请求先通过ActionContextCleanUp-->FilterDispatcher 
    3、FilterDispatcher通过ActionMapper来决定这个Request需要调用哪个Action 
    4、如果ActionMapper决定调用某个Action,FilterDispatcher把请求的处理交给ActionProxy,这儿已经转到它的Delegate--Dispatcher来执行 
    5、ActionProxy根据ActionMapping和ConfigurationManager找到需要调用的Action类 
    6、ActionProxy创建一个ActionInvocation的实例 
    7、ActionInvocation调用真正的Action,当然这涉及到相关拦截器的调用 
    8、Action执行完毕,ActionInvocation创建Result并返回,当然,如果要在返回之前做些什么,可以实现PreResultListener。添加PreResultListener可以在Interceptor中实现,不知道其它还有什么方式? 


    Struts2(2.1.2)部分源码阅读 
        从org.apache.struts2.dispatcher.FilterDispatcher开始 
        //创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析,读取对应Action的地方 
      

    Java代码  收藏代码
    1. public void init(FilterConfig filterConfig) throws ServletException {  
    2.        try {  
    3.            this.filterConfig = filterConfig;  
    4.   
    5.            initLogging();  
    6.   
    7.            dispatcher = createDispatcher(filterConfig);  
    8.            dispatcher.init();  
    9.            dispatcher.getContainer().inject(this);  
    10.            //读取初始参数pakages,调用parse(),解析成类似/org/apache/struts2/static,/template的数组  
    11.            String param = filterConfig.getInitParameter("packages");  
    12.            String packages = "org.apache.struts2.static template org.apache.struts2.interceptor.debugging";  
    13.            if (param != null) {  
    14.                packages = param + " " + packages;  
    15.            }  
    16.            this.pathPrefixes = parse(packages);  
    17.        } finally {  
    18.            ActionContext.setContext(null);  
    19.        }  
    20.    }  
    21.     顺着流程我们看Disptcher的init方法。init方法里就是初始读取一些配置文件等,先看init_DefaultProperties,主要是读取properties配置文件。  
    22.    private void init_DefaultProperties() {  
    23.        configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());  
    24.    }  
    25.    打开DefaultPropertiesProvider  
    26.    public void register(ContainerBuilder builder, LocatableProperties props)  
    27.            throws ConfigurationException {  
    28.          
    29.        Settings defaultSettings = null;  
    30.        try {  
    31.            defaultSettings = new PropertiesSettings("org/apache/struts2/default");  
    32.        } catch (Exception e) {  
    33.            throw new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", e);  
    34.        }  
    35.          
    36.        loadSettings(props, defaultSettings);  
    37.    }  
    38.   
    39.    //PropertiesSettings  
    40.    //读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写  
    41.    public PropertiesSettings(String name) {  
    42.          
    43.        URL settingsUrl = ClassLoaderUtils.getResource(name + ".properties", getClass());  
    44.          
    45.        if (settingsUrl == null) {  
    46.            LOG.debug(name + ".properties missing");  
    47.            settings = new LocatableProperties();  
    48.            return;  
    49.        }  
    50.          
    51.        settings = new LocatableProperties(new LocationImpl(null, settingsUrl.toString()));  
    52.   
    53.        // Load settings  
    54.        InputStream in = null;  
    55.        try {  
    56.            in = settingsUrl.openStream();  
    57.            settings.load(in);  
    58.        } catch (IOException e) {  
    59.            throw new StrutsException("Could not load " + name + ".properties:" + e, e);  
    60.        } finally {  
    61.            if(in != null) {  
    62.                try {  
    63.                    in.close();  
    64.                } catch(IOException io) {  
    65.                    LOG.warn("Unable to close input stream", io);  
    66.                }  
    67.            }  
    68.        }  
    69.    }  

        再来看init_TraditionalXmlConfigurations方法,这个是读取struts-default.xml和Struts.xml的方法。 
        private void init_TraditionalXmlConfigurations() { 
            //首先读取web.xml中的config初始参数值 
            //如果没有配置就使用默认的"struts-default.xml,struts-plugin.xml,struts.xml", 
            //这儿就可以看出为什么默认的配置文件必须取名为这三个名称了 
            //如果不想使用默认的名称,直接在web.xml中配置config初始参数即可 
          

    Java代码  收藏代码
    1. String configPaths = initParams.get("config");  
    2.        if (configPaths == null) {  
    3.            configPaths = DEFAULT_CONFIGURATION_PATHS;  
    4.        }  
    5.        String[] files = configPaths.split("\s*[,]\s*");  
    6.        //依次解析配置文件,xwork.xml单独解析  
    7.        for (String file : files) {  
    8.            if (file.endsWith(".xml")) {  
    9.                if ("xwork.xml".equals(file)) {  
    10.                    configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));  
    11.                } else {  
    12.                    configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));  
    13.                }  
    14.            } else {  
    15.                throw new IllegalArgumentException("Invalid configuration file name");  
    16.            }  
    17.        }  
    18.    }  

        对于其它配置文件只用StrutsXmlConfigurationProvider,此类继承XmlConfigurationProvider,而XmlConfigurationProvider又实现ConfigurationProvider接口。类XmlConfigurationProvider负责配置文件的读取和解析,addAction()方法负责读取<action>标签,并将数据保存在ActionConfig中;addResultTypes()方法负责将<result-type>标签转化为ResultTypeConfig对象;loadInterceptors()方法负责将<interceptor>标签转化为InterceptorConfi对象;loadInterceptorStack()方法负责将<interceptor-ref>标签转化为InterceptorStackConfig对象;loadInterceptorStacks()方法负责将<interceptor-stack>标签转化成InterceptorStackConfig对象。而上面的方法最终会被addPackage()方法调用,将所读取到的数据汇集到PackageConfig对象中。来看XmlConfigurationProvider的源代码,详细的我自己也就大体浏览了一下,各位可以自己研读。 
      

    Java代码  收藏代码
    1. protected PackageConfig addPackage(Element packageElement) throws ConfigurationException {  
    2.        PackageConfig.Builder newPackage = buildPackageContext(packageElement);  
    3.   
    4.        if (newPackage.isNeedsRefresh()) {  
    5.            return newPackage.build();  
    6.        }  
    7.        .  
    8.   
    9.        addResultTypes(newPackage, packageElement);  
    10.        loadInterceptors(newPackage, packageElement);  
    11.        loadDefaultInterceptorRef(newPackage, packageElement);  
    12.        loadDefaultClassRef(newPackage, packageElement);  
    13.        loadGlobalResults(newPackage, packageElement);  
    14.        loadGobalExceptionMappings(newPackage, packageElement);  
    15.        NodeList actionList = packageElement.getElementsByTagName("action");  
    16.   
    17.        for (int i = 0; i  docs = new ArrayList<document>();  
    18.        if (!includedFileNames.contains(fileName)) {  
    19.                  
    20.                Element rootElement = doc.getDocumentElement();  
    21.                NodeList children = rootElement.getChildNodes();  
    22.                int childSize = children.getLength();  
    23.   
    24.                for (int i = 0; i   
    25.                        if (nodeName.equals("include")) {  
    26.                            String includeFileName = child.getAttribute("file");  
    27.                            if(includeFileName.indexOf('*') != -1 ) {  
    28.                                ClassPathFinder wildcardFinder = new ClassPathFinder();  
    29.                                wildcardFinder.setPattern(includeFileName);  
    30.                                Vector<string> wildcardMatches = wildcardFinder.findMatches();  
    31.                                for (String match : wildcardMatches) {  
    32.                                    docs.addAll(loadConfigurationFiles(match, child));  
    33.                                }  
    34.                            }  
    35.                            else {  
    36.                                  
    37.                                docs.addAll(loadConfigurationFiles(includeFileName, child));      
    38.                            }      
    39.                    }  
    40.                }  
    41.                }  
    42.                docs.add(doc);  
    43.                loadedFileUrls.add(url.toString());  
    44.            }  
    45.        }  
    46.        return docs;  
    47.    }  
    48.    init_CustomConfigurationProviders方式初始自定义的Provider,配置类全名和实现ConfigurationProvider接口,用逗号隔开即可。   
    49.    private void init_CustomConfigurationProviders() {  
    50.        String configProvs = initParams.get("configProviders");  
    51.        if (configProvs != null) {  
    52.            String[] classes = configProvs.split("\s*[,]\s*");  
    53.            for (String cname : classes) {  
    54.                try {  
    55.                    Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());  
    56.                    ConfigurationProvider prov = (ConfigurationProvider)cls.newInstance();  
    57.                    configurationManager.addConfigurationProvider(prov);  
    58.                }  
    59.                  
    60.            }  
    61.        }  
    62.    }  
    63.    好了,现在再回到FilterDispatcher,每次发送一个Request,FilterDispatcher都会调用doFilter方法。  
    64.    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {  
    65.   
    66.        HttpServletRequest request = (HttpServletRequest) req;  
    67.        HttpServletResponse response = (HttpServletResponse) res;  
    68.        ServletContext servletContext = getServletContext();  
    69.   
    70.        String timerKey = "FilterDispatcher_doFilter: ";  
    71.        try {  
    72.            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();  
    73.            ActionContext ctx = new ActionContext(stack.getContext());  
    74.            ActionContext.setContext(ctx);  
    75.              
    76.            UtilTimerStack.push(timerKey);  
    77.            //根据content type来使用不同的Request封装,可以参见Dispatcher的wrapRequest  
    78.            request = prepareDispatcherAndWrapRequest(request, response);  
    79.            ActionMapping mapping;  
    80.            try {  
    81.                //根据url取得对应的Action的配置信息--ActionMapping,actionMapper是通过Container的inject注入的  
    82.                mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());  
    83.            } catch (Exception ex) {  
    84.                log.error("error getting ActionMapping", ex);  
    85.                dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);  
    86.                return;  
    87.            }  
    88.            //如果找不到对应的action配置,则直接返回。比如你输入***.jsp等等  
    89.            //这儿有个例外,就是如果path是以“/struts”开头,则到初始参数packages配置的包路径去查找对应的静态资源并输出到页面流中,当然.class文件除外。如果再没有则跳转到404  
    90.            if (mapping == null) {  
    91.                // there is no action in this request, should we look for a static resource?  
    92.                String resourcePath = RequestUtils.getServletPath(request);  
    93.   
    94.                if ("".equals(resourcePath) && null != request.getPathInfo()) {  
    95.                    resourcePath = request.getPathInfo();  
    96.                }  
    97.   
    98.                if (serveStatic && resourcePath.startsWith("/struts")) {  
    99.                    String name = resourcePath.substring("/struts".length());  
    100.                    findStaticResource(name, request, response);  
    101.                } else {  
    102.                    chain.doFilter(request, response);  
    103.                }  
    104.                return;  
    105.            }  
    106.            //正式开始Action的方法了  
    107.            dispatcher.serviceAction(request, response, servletContext, mapping);  
    108.   
    109.        } finally {  
    110.            try {  
    111.                ActionContextCleanUp.cleanUp(req);  
    112.            } finally {  
    113.                UtilTimerStack.pop(timerKey);  
    114.            }  
    115.        }  
    116.    }  
    117.    Dispatcher类的serviceAction方法:  
    118.    public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping) throws ServletException {  
    119.   
    120.        Map<string object> extraContext = createContextMap(request, response, mapping, context);  
    121.   
    122.        // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action  
    123.        ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);  
    124.        if (stack != null) {  
    125.            extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));  
    126.        }  
    127.   
    128.        String timerKey = "Handling request from Dispatcher";  
    129.        try {  
    130.            UtilTimerStack.push(timerKey);  
    131.            String namespace = mapping.getNamespace();  
    132.            String name = mapping.getName();  
    133.            String method = mapping.getMethod();  
    134.   
    135.            Configuration config = configurationManager.getConfiguration();  
    136.            ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(  
    137.                    namespace, name, method, extraContext, truefalse);  
    138.   
    139.            request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());  
    140.   
    141.            // if the ActionMapping says to go straight to a result, do it!  
    142.            if (mapping.getResult() != null) {  
    143.                Result result = mapping.getResult();  
    144.                result.execute(proxy.getInvocation());  
    145.            } else {  
    146.                proxy.execute();  
    147.            }  
    148.   
    149.            // If there was a previous value stack then set it back onto the request  
    150.            if (stack != null) {  
    151.                request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);  
    152.            }  
    153.        } catch (ConfigurationException e) {  
    154.            LOG.error("Could not find action or result", e);  
    155.            sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);  
    156.        } catch (Exception e) {  
    157.            sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);  
    158.        } finally {  
    159.            UtilTimerStack.pop(timerKey);  
    160.        }  
    161.    }  
    162.    第一句createContextMap()方法,该方法主要把Application、Session、Request的key value值拷贝到Map中,并放在HashMap<string>中,可以参见createContextMap方法:  
    163.    public Map<string> createContextMap(HttpServletRequest request, HttpServletResponse response,  
    164.            ActionMapping mapping, ServletContext context) {  
    165.   
    166.        // request map wrapping the http request objects  
    167.        Map requestMap = new RequestMap(request);  
    168.        // parameters map wrapping the http parameters.  ActionMapping parameters are now handled and applied separately  
    169.        Map params = new HashMap(request.getParameterMap());  
    170.        // session map wrapping the http session  
    171.        Map session = new SessionMap(request);  
    172.        // application map wrapping the ServletContext  
    173.        Map application = new ApplicationMap(context);  
    174.        Map<string> extraContext = createContextMap(requestMap, params, session, application, request, response, context);  
    175.        extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);  
    176.        return extraContext;  
    177.    }  
    178.    后面才是最主要的--ActionProxy,ActionInvocation。ActionProxy是Action的一个代理类,也就是说Action的调用是通过ActionProxy实现的,其实就是调用了ActionProxy.execute()方法,而该方法又调用了ActionInvocation.invoke()方法。归根到底,最后调用的是DefaultActionInvocation.invokeAction()方法。先看DefaultActionInvocation的init方法。  
    179.    public void init(ActionProxy proxy) {  
    180.        this.proxy = proxy;  
    181.        Map contextMap = createContextMap();  
    182.   
    183.        // Setting this so that other classes, like object factories, can use the ActionProxy and other  
    184.        // contextual information to operate  
    185.        ActionContext actionContext = ActionContext.getContext();  
    186.   
    187.        if(actionContext != null) {  
    188.            actionContext.setActionInvocation(this);  
    189.        }  
    190.        //创建Action,可Struts2里是每次请求都新建一个Action  
    191.        createAction(contextMap);  
    192.   
    193.        if (pushAction) {  
    194.            stack.push(action);  
    195.            contextMap.put("action", action);  
    196.        }  
    197.   
    198.        invocationContext = new ActionContext(contextMap);  
    199.        invocationContext.setName(proxy.getActionName());  
    200.   
    201.        // get a new List so we don't get problems with the iterator if someone changes the list  
    202.        List interceptorList = new ArrayList(proxy.getConfig().getInterceptors());  
    203.        interceptors = interceptorList.iterator();  
    204.    }  
    205.   
    206.    protected void createAction(Map contextMap) {  
    207.        // load action  
    208.        String timerKey = "actionCreate: "+proxy.getActionName();  
    209.        try {  
    210.            UtilTimerStack.push(timerKey);  
    211.            //这儿默认建立Action是StrutsObjectFactory,实际中我使用的时候都是使用Spring创建的Action,这个时候使用的是SpringObjectFactory  
    212.            action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);  
    213.        }   
    214.        ..  
    215.        } finally {  
    216.            UtilTimerStack.pop(timerKey);  
    217.        }  
    218.   
    219.        if (actionEventListener != null) {  
    220.            action = actionEventListener.prepare(action, stack);  
    221.        }  
    222.    }  
    223.   
    224.    接下来看看DefaultActionInvocation 的invoke方法。   
    225.   public String invoke() throws Exception {  
    226.        String profileKey = "invoke: ";  
    227.        try {  
    228.            UtilTimerStack.push(profileKey);  
    229.              
    230.            if (executed) {  
    231.                throw new IllegalStateException("Action has already executed");  
    232.            }  
    233.                //先执行interceptors  
    234.            if (interceptors.hasNext()) {  
    235.                final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();  
    236.                UtilTimerStack.profile("interceptor: "+interceptor.getName(),   
    237.                        new UtilTimerStack.ProfilingBlock<string>() {  
    238.                            public String doProfiling() throws Exception {  
    239.                                resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);  
    240.                                return null;  
    241.                            }  
    242.                });  
    243.            } else {  
    244.                        //interceptor执行完了之后执行action  
    245.                resultCode = invokeActionOnly();  
    246.            }  
    247.   
    248.            // this is needed because the result will be executed, then control will return to the Interceptor, which will  
    249.            // return above and flow through again  
    250.            if (!executed) {  
    251.                        //在Result返回之前调用preResultListeners  
    252.                if (preResultListeners != null) {  
    253.                    for (Iterator iterator = preResultListeners.iterator();  
    254.                        iterator.hasNext();) {  
    255.                        PreResultListener listener = (PreResultListener) iterator.next();  
    256.                          
    257.                        String _profileKey="preResultListener: ";  
    258.                        try {  
    259.                            UtilTimerStack.push(_profileKey);  
    260.                            listener.beforeResult(this, resultCode);  
    261.                        }  
    262.                        finally {  
    263.                            UtilTimerStack.pop(_profileKey);  
    264.                        }  
    265.                    }  
    266.                }  
    267.   
    268.                // now execute the result, if we're supposed to  
    269.                if (proxy.getExecuteResult()) {  
    270.                    executeResult();  
    271.                }  
    272.   
    273.                executed = true;  
    274.            }  
    275.   
    276.            return resultCode;  
    277.        }  
    278.        finally {  
    279.            UtilTimerStack.pop(profileKey);  
    280.        }  
    281.    }  

        看程序中的if(interceptors.hasNext())语句,当然,interceptors里存储的是interceptorMapping列表(它包括一个Interceptor和一个name),所有的截拦器必须实现Interceptor的intercept方法,而该方法的参数恰恰又是ActionInvocation,在intercept方法中还是调用invocation.invoke(),从而实现了一个Interceptor链的调用。当所有的Interceptor执行完,最后调用invokeActionOnly方法来执行Action相应的方法。 
      

    Java代码  收藏代码
    1.  protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {  
    2.         String methodName = proxy.getMethod();  
    3.         String timerKey = "invokeAction: "+proxy.getActionName();  
    4.         try {  
    5.             UtilTimerStack.push(timerKey);  
    6.               
    7.             boolean methodCalled = false;  
    8.             Object methodResult = null;  
    9.             Method method = null;  
    10.             try {  
    11.                 //获得需要执行的方法  
    12.                 method = getAction().getClass().getMethod(methodName, new Class[0]);  
    13.             } catch (NoSuchMethodException e) {  
    14.                 //如果没有对应的方法,则使用do+Xxxx来再次获得方法  
    15.                 try {  
    16.                     String altMethodName = "do" + methodName.substring(01).toUpperCase() + methodName.substring(1);  
    17.                     method = getAction().getClass().getMethod(altMethodName, new Class[0]);  
    18.                 } catch (NoSuchMethodException e1) {  
    19.                     // well, give the unknown handler a shot  
    20.                     if (unknownHandler != null) {  
    21.                         try {  
    22.                             methodResult = unknownHandler.handleUnknownActionMethod(action, methodName);  
    23.                             methodCalled = true;  
    24.                         } catch (NoSuchMethodException e2) {  
    25.                             // throw the original one  
    26.                             throw e;  
    27.                         }  
    28.                     } else {  
    29.                         throw e;  
    30.                     }  
    31.                 }  
    32.             }  
    33.               
    34.             if (!methodCalled) {  
    35.                 methodResult = method.invoke(action, new Object[0]);  
    36.             }  
    37.             //根据不同的Result类型返回不同值  
    38.             //如输出流Result  
    39.             if (methodResult instanceof Result) {  
    40.                 this.explicitResult = (Result) methodResult;  
    41.                 return null;  
    42.             } else {  
    43.                 return (String) methodResult;  
    44.             }  
    45.         } catch (NoSuchMethodException e) {  
    46.             throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");  
    47.         } catch (InvocationTargetException e) {  
    48.             // We try to return the source exception.  
    49.             Throwable t = e.getTargetException();  
    50.   
    51.             if (actionEventListener != null) {  
    52.                 String result = actionEventListener.handleException(t, getStack());  
    53.                 if (result != null) {  
    54.                     return result;  
    55.                 }  
    56.             }  
    57.             if (t instanceof Exception) {  
    58.                 throw(Exception) t;  
    59.             } else {  
    60.                 throw e;  
    61.             }  
    62.         } finally {  
    63.             UtilTimerStack.pop(timerKey);  
    64.         }  
    65.     }  
    66.     好了,action执行完了,还要根据ResultConfig返回到view,也就是在invoke方法中调用executeResult方法。  
    67.     private void executeResult() throws Exception {  
    68.         //根据ResultConfig创建Result  
    69.         result = createResult();  
    70.         String timerKey = "executeResult: "+getResultCode();  
    71.         try {  
    72.             UtilTimerStack.push(timerKey);  
    73.             if (result != null) {  
    74.                 //这儿正式执行:)  
    75.                 //可以参考Result的实现,如用了比较多的ServletDispatcherResult,ServletActionRedirectResult,ServletRedirectResult  
    76.                 result.execute(this);  
    77.             } else if (resultCode != null && !Action.NONE.equals(resultCode)) {  
    78.                 throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()   
    79.                         + " and result " + getResultCode(), proxy.getConfig());  
    80.             } else {  
    81.                 if (LOG.isDebugEnabled()) {  
    82.                     LOG.debug("No result returned for action "+getAction().getClass().getName()+" at "+proxy.getConfig().getLocation());  
    83.                 }  
    84.             }  
    85.         } finally {  
    86.             UtilTimerStack.pop(timerKey);  
    87.         }  
    88.     }  
    89.     public Result createResult() throws Exception {  
    90.         if (explicitResult != null) {  
    91.             Result ret = explicitResult;  
    92.             explicitResult = null;;  
    93.             return ret;  
    94.         }  
    95.         ActionConfig config = proxy.getConfig();  
    96.         Map results = config.getResults();  
    97.         ResultConfig resultConfig = null;  
    98.         synchronized (config) {  
    99.             try {  
    100.                 //根据result名称获得ResultConfig,resultCode就是result的name  
    101.                 resultConfig = (ResultConfig) results.get(resultCode);  
    102.             } catch (NullPointerException e) {  
    103.             }  
    104.             if (resultConfig == null) {  
    105.                 //如果找不到对应name的ResultConfig,则使用name为*的Result  
    106.                 resultConfig = (ResultConfig) results.get("*");  
    107.             }  
    108.         }  
    109.         if (resultConfig != null) {  
    110.             try {  
    111.                 //参照StrutsObjectFactory的代码  
    112.                 Result result = objectFactory.buildResult(resultConfig, invocationContext.getContextMap());  
    113.                 return result;  
    114.             } catch (Exception e) {  
    115.                 LOG.error("There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);  
    116.                 throw new XWorkException(e, resultConfig);  
    117.             }  
    118.         } else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandler != null) {  
    119.             return unknownHandler.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);  
    120.         }  
    121.         return null;  
    122.     }  
    123.     //StrutsObjectFactory  
    124.     public Result buildResult(ResultConfig resultConfig, Map extraContext) throws Exception {  
    125.         String resultClassName = resultConfig.getClassName();  
    126.         if (resultClassName == null)  
    127.             return null;  
    128.         //创建Result,因为Result是有状态的,所以每次请求都新建一个  
    129.         Object result = buildBean(resultClassName, extraContext);  
    130.         //这句很重要,后面将会谈到,reflectionProvider参见OgnlReflectionProvider;  
    131.         //resultConfig.getParams()就是result配置文件里所配置的参数<param>  
    132.         //setProperties方法最终调用的是Ognl类的setValue方法  
    133.         //这句其实就是把param名值设置到根对象result上  
    134.         reflectionProvider.setProperties(resultConfig.getParams(), result, extraContext);  
    135.         if (result instanceof Result)  
    136.             return (Result) result;  
    137.         throw new ConfigurationException(result.getClass().getName() + " does not implement Result.");  
    138.     }  
    139.     最后补充一下,Struts2的查找值和设置值都是使用Ognl来实现的。关于Ognl的介绍可以到其官方网站查看http://www.ognl.org/,我在网上也找到另外一篇http://www.javaeye.com/topic/254684和http://www.javaeye.com/topic/223612。完了来看下面这段小测试程序(其它的Ognl的测试可以自己添加)。  
    140. public class TestOgnl {  
    141.       
    142.     private User user;  
    143.     private Map context;  
    144.       
    145.     @Before  
    146.     public void setUp() throws Exception {  
    147.       
    148.     }  
    149.   
    150.     @Test  
    151.     public void ognlGetValue() throws Exception {  
    152.     reset();  
    153.     Assert.assertEquals("myyate", Ognl.getValue("name", user));  
    154.     Assert.assertEquals("cares", Ognl.getValue("dept.name", user));  
    155.     Assert.assertEquals("myyate", Ognl.getValue("name", context, user));  
    156.     Assert.assertEquals("contextmap", Ognl.getValue("#name", context, user));  
    157.     Assert.assertEquals("parker", Ognl.getValue("#pen", context, user));  
    158.     }  
    159.       
    160.     @Test  
    161.     public void ognlSetValue() throws Exception {  
    162.     reset();  
    163.     Ognl.setValue("name", user, "myyateC");  
    164.     Assert.assertEquals("myyateC", Ognl.getValue("name", user));  
    165.       
    166.     Ognl.setValue("dept.name", user, "caresC");  
    167.     Assert.assertEquals("caresC", Ognl.getValue("dept.name", user));  
    168.       
    169.     Assert.assertEquals("contextmap", Ognl.getValue("#name", context, user));  
    170.     Ognl.setValue("#name", context, user, "contextmapC");  
    171.     Assert.assertEquals("contextmapC", Ognl.getValue("#name", context, user));  
    172.       
    173.     Assert.assertEquals("parker", Ognl.getValue("#pen", context, user));  
    174.     Ognl.setValue("#name", context, user, "parkerC");  
    175.     Assert.assertEquals("parkerC", Ognl.getValue("#name", context, user));  
    176.     }  
    177.       
    178.     public static void main(String[] args) throws Exception {  
    179.     JUnitCore.runClasses(TestOgnl.class);  
    180.     }  
    181.       
    182.     private void reset() {  
    183.     user = new User("myyate"new Dept("cares"));  
    184.     context = new OgnlContext();  
    185.     context.put("pen""parker");  
    186.     context.put("name""contextmap");  
    187.     }  
    188. }  
    189.   
    190. class User {  
    191.     public User(String name, Dept dept) {  
    192.     this.name = name;  
    193.     this.dept = dept;  
    194.     }  
    195.     String name;  
    196.     private Dept dept;  
    197.     public Dept getDept() {  
    198.         return dept;  
    199.     }  
    200.     public String getName() {  
    201.         return name;  
    202.     }  
    203.     public void setDept(Dept dept) {  
    204.         this.dept = dept;  
    205.     }  
    206.     public void setName(String name) {  
    207.         this.name = name;  
    208.     }  
    209. }  
    210.   
    211. class Dept {  
    212.     public Dept(String name) {  
    213.     this.name = name;  
    214.     }  
    215.     private String name;  
    216.     public String getName() {  
    217.         return name;  
    218.     }  
    219.     public void setName(String name) {  
    220.         this.name = name;  
    221.     }  
    222. }  
  • 相关阅读:
    mysql 远程登陆不上
    hdu 5339 Untitled【搜索】
    SqlServer 书目
    passwordauthentication yes
    oracle 11g RAC ocfs2
    Oracle 11g RAC database on ASM, ACFS or OCFS2
    CentOS ips bonding
    Oracle 11g RAC features
    openStack 王者归来之 trivial matters
    openstack windows 2008 img
  • 原文地址:https://www.cnblogs.com/heartstage/p/3410390.html
Copyright © 2011-2022 走看看