`

Struts2源码阅读

 
阅读更多

Struts包介绍

http://www.blogjava.net/lzhidj/archive/2008/07/10/213898.html )(大部分叙述性的文字和图从其文中拷贝):

包名

说明

org.apache.struts2. components

该包封装视图组件, Struts2在视图组件上有了很大加强,不仅增加了组件的属性个数,更新增了几个非常有用的组件,如 updownselect doubleselect datetimepicker token tree等。

另外, Struts2可视化视图组件开始支持主题 (theme),缺省情况下,使用自带的缺省主题,如果要自定义页面效果,需要将组件的 theme属性设置为 simple

org.apache.struts2. config

该包定义与配置相关的接口和类。实际上,工程中的 xml properties文件的读取和解析都是由 WebWork完成的, Struts只做了少量的工作。

org.apache.struts2.dispatcher

Struts2的核心包,最重要的类都放在该包中。

org.apache.struts2.impl

该包只定义了 3个类,他们是 StrutsActionProxy StrutsActionProxyFactory StrutsObjectFactory,这三个类都是对 xwork的扩展。

org.apache.struts2.interceptor

定义内置的截拦器。

org.apache.struts2.util

实用包。

org.apache.struts2.validators

只定义了一个类: DWRValidator

org.apache.struts2.views

提供 freemarker jsp velocity等不同类型的页面呈现。

下表是对一些重要类的说明:

类名

说明

org.apache.struts2.dispatcher. Dispatcher

该类有两个作用:

1、初始化

2、调用指定的 Action execute()方法。

org.apache.struts2.dispatcher. FilterDispatcher

    这是一个过滤器。文档中已明确说明,如果没有经验,配置时请将 url-pattern的值设成 /*

    该类有四个作用:

    1、执行 Action

    2、清理 ActionContext,避免内存泄漏

    3、处理静态内容( Serving static content

    4、为请求启动 xwork’s的截拦器链。

com.opensymphony.xwork2. ActionProxy

Action的代理接口。

com.opensymphony.xwork2. ctionProxyFactory

 生产 ActionProxy的工厂。

com.opensymphony.xwork2.ActionInvocation

负责调用 Action和截拦器。

com.opensymphony.xwork2.config.providers. XmlConfigurationProvider

负责 Struts2的配置文件的解析。


Struts体系结构

Struts工作机制
    1、客户端初始化一个指向Servlet容器(例如Tomcat)的请求;
    2、这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin);
    3、接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用某个Action;
    4、如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy;
    5、ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类;
    6、ActionProxy创建一个ActionInvocation的实例。
    7、ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。
    8、一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总 是,也可能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper。
Struts源码分析
    从org.apache.struts2.dispatcher.FilterDispatcher开始

  •    //创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析,读取对应Action。。。的地方
  •    public   void  init(FilterConfig filterConfig)  throws  ServletException {
  •           this .filterConfig = filterConfig;
  •          
  •         dispatcher = createDispatcher(filterConfig);
  •         dispatcher.init();
  •         //读取初始参数pakages,调用parse(),解析成类似/org/apache/struts2/static,/template的数组
  •         String param = filterConfig.getInitParameter( "packages" );
  •         String packages =  "org.apache.struts2.static template org.apache.struts2.interceptor.debugging" ;
  •          if  (param !=  null ) {
  •             packages = param +  " "  + packages;
  •         }
  •          this .pathPrefixes = parse(packages);
  •     }
  •     顾名思义,init方法里就是初始读取一些属性配置文件,先看init_DefaultProperties。
    1.      public   void  init() {
    2.          if  (configurationManager ==  null ) {
    3.             configurationManager =  new  ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
    4.         }
    5.         init_DefaultProperties();  // [1]
    6.         init_TraditionalXmlConfigurations();  // [2]
    7.         init_LegacyStrutsProperties();  // [3]
    8.         init_ZeroConfiguration();  // [4]
    9.         init_CustomConfigurationProviders();  // [5]
    10.         init_MethodConfigurationProvider();
    11.         init_FilterInitParameters() ;  // [6]
    12.         init_AliasStandardObjects() ;  // [7]
    13.         Container container = init_PreloadConfiguration();
    14.         init_CheckConfigurationReloading(container);
    15.         init_CheckWebLogicWorkaround(container);
    16.     }
    17.      private   void  init_DefaultProperties() {
    18.         configurationManager.addConfigurationProvider( new  DefaultPropertiesProvider());
    19.     }
    20.      //DefaultPropertiesProvider
    21.      public   void  register(ContainerBuilder builder, LocatableProperties props)
    22.              throws  ConfigurationException {
    23.         
    24.         Settings defaultSettings =  null ;
    25.          try  {
    26.             defaultSettings =  new  PropertiesSettings( "org/apache/struts2/default" );
    27.         }  catch  (Exception e) {
    28.              throw   new  ConfigurationException( "Could not find or error in org/apache/struts2/default.properties" , e);
    29.         }
    30.         
    31.         loadSettings(props, defaultSettings);
    32.     }
    33.      //PropertiesSettings
    34.      //读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写
    35.      public  PropertiesSettings(String name) {
    36.         
    37.         URL settingsUrl = ClassLoaderUtils.getResource(name +  ".properties" , getClass());
    38.         
    39.          if  (settingsUrl ==  null ) {
    40.             LOG.debug(name +  ".properties missing" );
    41.             settings =  new  LocatableProperties();
    42.              return ;
    43.         }
    44.          //settings的类型为LocatableProperties,继承Properties
    45.         settings =  new  LocatableProperties( new  LocationImpl( null , settingsUrl.toString()));
    46.          // Load settings
    47.         InputStream in =  null ;
    48.          try  {
    49.             in = settingsUrl.openStream();
    50.             settings.load(in);
    51.         }  catch  (IOException e) {
    52.              throw   new  StrutsException( "Could not load "  + name +  ".properties:"  + e, e);
    53.         }  finally  {
    54.              if (in !=  null ) {
    55.                  try  {
    56.                     in.close();
    57.                 }  catch (IOException io) {
    58.                     LOG.warn( "Unable to close input stream" , io);
    59.                 }
    60.             }
    61.         }
    62.     }
        再来看init_TraditionalXmlConfigurations方法,这个是读取Action配置的方法。
    1.      private   void  init_TraditionalXmlConfigurations() {
    2.          //首先读取web.xml中的config初始参数值
    3.          //如果没有配置就使用默认的"struts-default.xml,struts-plugin.xml,struts.xml",
    4.          //这儿就可以看出为什么默认的配置文件必须取名为这三个名称了
    5.          //如果不想使用默认的名称,直接在web.xml中配置config初始参数即可
    6.         String configPaths = initParams.get( "config" );
    7.          if  (configPaths ==  null ) {
    8.             configPaths = DEFAULT_CONFIGURATION_PATHS;
    9.         }
    10.         String[] files = configPaths.split( "//s*[,]//s*" );
    11.          //依次解析配置文件,xwork.xml单独解析
    12.          for  (String file : files) {
    13.              if  (file.endsWith( ".xml" )) {
    14.                  if  ( "xwork.xml" .equals(file)) {
    15.                     configurationManager.addConfigurationProvider( new  XmlConfigurationProvider(file,  false ));
    16.                 }  else  {
    17.                     configurationManager.addConfigurationProvider( new  StrutsXmlConfigurationProvider(file,  false , servletContext));
    18.                 }
    19.             }  else  {
    20.                  throw   new  IllegalArgumentException( "Invalid configuration file name" );
    21.             }
    22.         }
    23.     }
        对于其它配置文件只用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 对象中
    1.      protected  PackageConfig addPackage(Element packageElement)  throws  ConfigurationException {
    2.         PackageConfig.Builder newPackage = buildPackageContext(packageElement);
    3.          if  (newPackage.isNeedsRefresh()) {
    4.              return  newPackage.build();
    5.         }
    6.          if  (LOG.isDebugEnabled()) {
    7.             LOG.debug( "Loaded "  + newPackage);
    8.         }
    9.          // add result types (and default result) to this package
    10.         addResultTypes(newPackage, packageElement);
    11.          // load the interceptors and interceptor stacks for this package
    12.         loadInterceptors(newPackage, packageElement);
    13.          // load the default interceptor reference for this package
    14.         loadDefaultInterceptorRef(newPackage, packageElement);
    15.          // load the default class ref for this package
    16.         loadDefaultClassRef(newPackage, packageElement);
    17.          // load the global result list for this package
    18.         loadGlobalResults(newPackage, packageElement);
    19.          // load the global exception handler list for this package
    20.         loadGobalExceptionMappings(newPackage, packageElement);
    21.          // get actions
    22.         NodeList actionList = packageElement.getElementsByTagName( "action" );
    23.          for  ( int  i =  0 ; i < actionList.getLength(); i++) {
    24.             Element actionElement = (Element) actionList.item(i);
    25.             addAction(actionElement, newPackage);
    26.         }
    27.          // load the default action reference for this package
    28.         loadDefaultActionRef(newPackage, packageElement);
    29.         PackageConfig cfg = newPackage.build();
    30.         configuration.addPackageConfig(cfg.getName(), cfg);
    31.          return  cfg;
    32.     }
        这儿发现一个配置上的小东西,我的xwork2.0.*是没有的,但是看源码是看到xwork2.1.*是可以的。看如下代码:
    1.      private  List loadConfigurationFiles(String fileName, Element includeElement) {
    2.         List<Document> docs =  new  ArrayList<Document>();
    3.          if  (!includedFileNames.contains(fileName)) {
    4.             ...........
    5.                 Element rootElement = doc.getDocumentElement();
    6.                 NodeList children = rootElement.getChildNodes();
    7.                  int  childSize = children.getLength();
    8.                  for  ( int  i = 0; i < childSize; i++) {
    9.                     Node childNode = children.item(i);
    10.                      if  (childNode instanceof Element) {
    11.                         Element child = (Element) childNode;
    12.                         final String nodeName = child.getNodeName();
    13.                          //解析每个action配置是,对于include文件可以使用通配符*来进行配置
    14.                          //如Struts.xml中可配置成<include file="actions_*.xml"/>
    15.                          if  (nodeName.equals( "include" )) {
    16.                             String includeFileName = child.getAttribute( "file" );
    17.                              if (includeFileName.indexOf( '*' ) != -1 ) {
    18.                                  // handleWildCardIncludes(includeFileName, docs, child);
    19.                                 ClassPathFinder wildcardFinder =  new  ClassPathFinder();
    20.                                 wildcardFinder.setPattern(includeFileName);
    21.                                 Vector<String> wildcardMatches = wildcardFinder.findMatches();
    22.                                  for  (String match : wildcardMatches) {
    23.                                     docs.addAll(loadConfigurationFiles(match, child));
    24.                                 }
    25.                             }
    26.                              else  {
    27.                                 
    28.                                 docs.addAll(loadConfigurationFiles(includeFileName, child));    
    29.                             }    
    30.                     }
    31.                 }
    32.                 }
    33.                 docs.add(doc);
    34.                 loadedFileUrls.add(url.toString());
    35.             }
    36.         }
    37.          return  docs;
    38.     }
        init_CustomConfigurationProviders方式初始自定义的Provider,配置类全名和实现ConfigurationProvider接口就可以。
    1.      public   void  doFilter(ServletRequest req, ServletResponse res, FilterChain chain)  throws  IOException, ServletException {
    2.         HttpServletRequest request = (HttpServletRequest) req;
    3.         HttpServletResponse response = (HttpServletResponse) res;
    4.         ServletContext servletContext = getServletContext();
    5.         String timerKey =  "FilterDispatcher_doFilter: " ;
    6.          try  {
    7.             UtilTimerStack.push(timerKey);
    8.              //根据content type来使用不同的Request封装,可以参见Dispatcher的wrapRequest
    9.             request = prepareDispatcherAndWrapRequest(request, response);
    10.             ActionMapping mapping;
    11.              try  {
    12.                  //根据url取得对应的Action的配置信息--ActionMapping,actionMapper是通过Container的inject注入的
    13.                 mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
    14.             }  catch  (Exception ex) {
    15.                 LOG.error( "error getting ActionMapping" , ex);
    16.                 dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
    17.                  return ;
    18.             }
    19.              //如果找不到对应的action配置,则直接返回。比如你输入***.jsp等等
    20.             //这儿有个例外,就是如果path是以“/struts”开头,则到初始参数packages配置的包路径去查找对应的静态资源并输出到页面流中,当然.class文件除外。如果再没有则跳转到404
    21.           if  (mapping ==  null ) {
    22.                  // there is no action in this request, should we look for a static resource?
    23.                 String resourcePath = RequestUtils.getServletPath(request);
    24.                  if  ( "" .equals(resourcePath) &&  null  != request.getPathInfo()) {
    25.                     resourcePath = request.getPathInfo();
    26.                 }
    27.                  if  (serveStatic && resourcePath.startsWith( "/struts" )) {
    28.                     String name = resourcePath.substring( "/struts" .length());
    29.                     findStaticResource(name, request, response);
    30.                 }  else  {
    31.                      // this is a normal request, let it pass through
    32.                     chain.doFilter(request, response);
    33.                 }
    34.                  // The framework did its job here
    35.                  return ;
    36.             }
    37.              //正式开始执行Action的方法了
    38.             dispatcher.serviceAction(request, response, servletContext, mapping);
    39.         }  finally  {
    40.              try  {
    41.                 ActionContextCleanUp.cleanUp(req);
    42.             }  finally  {
    43.                 UtilTimerStack.pop(timerKey);
    44.             }
    45.         }
    46.     }
        来看Dispatcher类的serviceAction方法:
    1.      public   void  serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
    2.                               ActionMapping mapping)  throws  ServletException {
    3.         Map<String, Object> extraContext = createContextMap(request, response, mapping, context);
    4.          // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
    5.         ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
    6.          if  (stack !=  null ) {
    7.             extraContext.put(ActionContext.VALUE_STACK, ValueStackFactory.getFactory().createValueStack(stack));
    8.         }
    9.         String timerKey =  "Handling request from Dispatcher" ;
    10.          try  {
    11.             UtilTimerStack.push(timerKey);
    12.             String namespace = mapping.getNamespace();
    13.             String name = mapping.getName();
    14.             String method = mapping.getMethod();
    15.             Configuration config = configurationManager.getConfiguration();
    16.             ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory. class ).createActionProxy(namespace, name, extraContext,  true false );
    17.             proxy.setMethod(method);
    18.             request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
    19.              // if the ActionMapping says to go straight to a result, do it!
    20.              if  (mapping.getResult() !=  null ) {
    21.                 Result result = mapping.getResult();
    22.                 result.execute(proxy.getInvocation());
    23.             }  else  {
    24.                 proxy.execute();
    25.             }
    26.              // If there was a previous value stack then set it back onto the request
    27.              if  (stack !=  null ) {
    28.                 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
    29.             }
    30.         }  catch  (ConfigurationException e) {
    31.             LOG.error( "Could not find action or result" , e);
    32.             sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);
    33.         }  catch  (Exception e) {
    34.              throw   new  ServletException(e);
    35.         }  finally  {
    36.             UtilTimerStack.pop(timerKey);
    37.         }
    38.     }
        第一句createContextMap() 方法,该方法主要把Application、Session、Request的key value值拷贝到Map中,并放在HashMap<String,Object>中,可以参见createContextMap方法:
    1.      public  HashMap<String,Object> createContextMap(Map requestMap,
    2.                                     Map parameterMap,
    3.                                     Map sessionMap,
    4.                                     Map applicationMap,
    5.                                     HttpServletRequest request,
    6.                                     HttpServletResponse response,
    7.                                     ServletContext servletContext) {
    8.         HashMap<String,Object> extraContext =  new  HashMap<String,Object>();
    9.         extraContext.put(ActionContext.PARAMETERS,  new  HashMap(parameterMap));
    10.         extraContext.put(ActionContext.SESSION, sessionMap);
    11.         extraContext.put(ActionContext.APPLICATION, applicationMap);
    12.         Locale locale;
    13.          if  (defaultLocale !=  null ) {
    14.             locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
    15.         }  else  {
    16.             locale = request.getLocale();
    17.         }
    18.         extraContext.put(ActionContext.LOCALE, locale);
    19.          //extraContext.put(ActionContext.DEV_MODE, Boolean.valueOf(devMode));
    20.         extraContext.put(StrutsStatics.HTTP_REQUEST, request);
    21.         extraContext.put(StrutsStatics.HTTP_RESPONSE, response);
    22.         extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext);
    23.          // helpers to get access to request/session/application scope
    24.         extraContext.put( "request" , requestMap);
    25.         extraContext.put( "session" , sessionMap);
    26.         extraContext.put( "application" , applicationMap);
    27.         extraContext.put( "parameters" , parameterMap);
    28.         AttributeMap attrMap =  new  AttributeMap(extraContext);
    29.         extraContext.put( "attr" , attrMap);
    30.          return  extraContext;
    31.     }
        后面才是最主要的--ActionProxy,ActionInvocation。ActionProxy是Action的一个代理类,也就是说 Action的调用是通过ActionProxy实现的,其实就是调用了ActionProxy.execute()方法,而该方法又调用了 ActionInvocation.invoke()方法。归根到底,最后调用的是 DefaultActionInvocation.invokeAction()方法。先看DefaultActionInvocation的init方 法。
    1.      public   void  init(ActionProxy proxy) {
    2.          this .proxy = proxy;
    3.         Map contextMap = createContextMap();
    4.          //设置ActionContext,把ActionInvocation和Action压入ValueStack
    5.         ActionContext actionContext = ActionContext.getContext();
    6.          if (actionContext !=  null ) {
    7.             actionContext.setActionInvocation( this );
    8.         }
    9.          //创建Action,可以看出Struts2里是每次请求都新建一个Action,careateAction方法可以自己参考
    10.         createAction(contextMap);
    11.          if  (pushAction) {
    12.             stack.push(action);
    13.             contextMap.put( "action" , action);
    14.         }
    15.         invocationContext =  new  ActionContext(contextMap);
    16.         invocationContext.setName(proxy.getActionName());
    17.         List interceptorList =  new  ArrayList(proxy.getConfig().getInterceptors());
    18.         interceptors = interceptorList.iterator();
    19.     }
    1.      protected   void  createAction(Map contextMap) {
    2.         String timerKey =  "actionCreate: " +proxy.getActionName();
    3.          try  {
    4.             UtilTimerStack.push(timerKey);
    5.              //这儿默认建立Action是StrutsObjectFactory,实际中我使用的时候都是使用Spring创建的Action,这个时候使用的是SpringObjectFactory
    6.             action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);
    7.         }
    8.          ....... 
    9.           catch  (Exception e) {
    10.             ........
    11.              throw   new  XWorkException(gripe, e, proxy.getConfig());
    12.         }  finally  {
    13.             UtilTimerStack.pop(timerKey);
    14.         }
    15.          if  (actionEventListener !=  null ) {
    16.             action = actionEventListener.prepare(action, stack);
    17.         }
    18.     }
        接下来看看DefaultActionInvocation 的invoke方法。
    1.      public  String invoke()  throws  Exception {
    2.         String profileKey =  "invoke: " ;
    3.          try  {
    4.             UtilTimerStack.push(profileKey);
    5.             
    6.              if  (executed) {
    7.                  throw   new  IllegalStateException( "Action has already executed" );
    8.             }
    9.                  //先执行interceptors
    10.              if  (interceptors.hasNext()) {
    11.                  final  InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
    12.                 UtilTimerStack.profile( "interceptor: " +interceptor.getName(), 
    13.                          new  UtilTimerStack.ProfilingBlock<String>() {
    14.                              public  String doProfiling()  throws  Exception {
    15.                                 resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation. this );
    16.                                  return   null ;
    17.                             }
    18.                 });
    19.             }  else  {
    20.                          //interceptor执行完了之后执行action
    21.                 resultCode = invokeActionOnly();
    22.             }
    23.              if  (!executed) {
    24.                  if  (preResultListeners !=  null ) {
    25.                      for  (Iterator iterator = preResultListeners.iterator();
    26.                         iterator.hasNext();) {
    27.                         PreResultListener listener = (PreResultListener) iterator.next();
    28.                         
    29.                         String _profileKey= "preResultListener: " ;
    30.                          try  {
    31.                             UtilTimerStack.push(_profileKey);
    32.                             listener.beforeResult( this , resultCode);
    33.                         }
    34.                          finally  {
    35.                             UtilTimerStack.pop(_profileKey);
    36.                         }
    37.                     }
    38.                 }
    39.                  // now execute the result, if we're supposed to
    40.                  if  (proxy.getExecuteResult()) {
    41.                     executeResult();
    42.                 }
    43.                 executed =  true ;
    44.             }
    45.              return  resultCode;
    46.         }
    47.          finally  {
    48.             UtilTimerStack.pop(profileKey);
    49.         }
    50.     }
         看程序中的if(interceptors.hasNext() )语句,当然,interceptors里存储的是 interceptorMapping列表(它包括一个Interceptor和一个name), 所有的截拦器必须实现 Interceptor的intercept 方法,而该方法的参数恰恰又是 ActionInvocation ,在 intercept 方法中还是调用 invocation.invoke() ,从而实现了一个 Interceptor链的调用。当所有的Interceptor执行完,最后调用invokeActionOnly方法来执行Action相应的方法。
    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.                  //获得Action对应的方法
    12.                 method = getAction().getClass().getMethod(methodName,  new  Class[ 0 ]);
    13.             }  catch  (NoSuchMethodException e) {
    14.                  try  {
    15.                      //如果没有对应的方法,则使用do+Xxxx来再次获得方法
    16.                     String altMethodName =  "do"  + methodName.substring( 0 1 ).toUpperCase() + methodName.substring( 1 );
    17.                     method = getAction().getClass().getMethod(altMethodName,  new  Class[ 0 ]);
    18.                 }  catch  (NoSuchMethodException e1) {
    19.                     .....
    20.                 }
    21.             }
    22.             
    23.              if  (!methodCalled) {
    24.                 methodResult = method.invoke(action,  new  Object[ 0 ]);
    25.             }
    26.              //根据不同的Result类型返回不同值
    27.              if  (methodResult  instanceof  Result) {
    28.                  this .explicitResult = (Result) methodResult;
    29.                  return   null ;
    30.             }  else  {
    31.                  return  (String) methodResult;
    32.             }
    33.         }
    34.         ....
    35.         }  finally  {
    36.             UtilTimerStack.pop(timerKey);
    37.         }
    38.     }
          好了,action执行完了,还要根据ResultConfig返回到view,也就是在invoke方法中调用executeResult方法。
    1.      private   void  executeResult()  throws  Exception {
    2.          //根据ResultConfig创建Result
    3.         result = createResult();
    4.         String timerKey =  "executeResult: " +getResultCode();
    5.          try  {
    6.             UtilTimerStack.push(timerKey);
    7.              if  (result !=  null ) {
    8.                  //这儿正式执行:)
    9.                 //可以参考Result的实现,如用了比较多的 ServletDispatcherResult,ServletActionRedirectResult,ServletRedirectResult
    10.                 result.execute( this );
    11.             }  else   if  (resultCode !=  null  && !Action.NONE.equals(resultCode)) {
    12.                  throw   new  ConfigurationException( "No result defined for action "  + getAction().getClass().getName() 
    13.                         +  " and result "  + getResultCode(), proxy.getConfig());
    14.             }  else  {
    15.                  if  (LOG.isDebugEnabled()) {
    16.                     LOG.debug( "No result returned for action " +getAction().getClass().getName()+ " at " +proxy.getConfig().getLocation());
    17.                 }
    18.             }
    19.         }  finally  {
    20.             UtilTimerStack.pop(timerKey);
    21.         }
    22.     }
    1.      public  Result createResult()  throws  Exception {
    2.          if  (explicitResult !=  null ) {
    3.             Result ret = explicitResult;
    4.             explicitResult =  null ;;
    5.              return  ret;
    6.         }
    7.         ActionConfig config = proxy.getConfig();
    8.         Map results = config.getResults();
    9.         ResultConfig resultConfig =  null ;
    10.          synchronized  (config) {
    11.              try  {
    12.                  //根据result名称获得ResultConfig,resultCode就是result的name
    13.                 resultConfig = (ResultConfig) results.get(resultCode);
    14.             }  catch  (NullPointerException e) {
    15.             }
    16.              if  (resultConfig ==  null ) {
    17.                  //如果找不到对应name的ResultConfig,则使用name为*的Result
    18.                 resultConfig = (ResultConfig) results.get( "*" );
    19.             }
    20.         }
    21.          if  (resultConfig !=  null ) {
    22.              try  {
    23.                  //参照StrutsObjectFactory的代码
    24.                 Result result = objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
    25.                  return  result;
    26.             }  catch  (Exception e) {
    27.                 LOG.error( "There was an exception while instantiating the result of type "  + resultConfig.getClassName(), e);
    28.                  throw   new  XWorkException(e, resultConfig);
    29.             }
    30.         }  else   if  (resultCode !=  null  && !Action.NONE.equals(resultCode) && unknownHandler !=  null ) {
    31.              return  unknownHandler.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);
    32.         }
    33.          return   null ;
    34.     }
    35.     // StrutsObjectFactory
    36.     public  Result buildResult(ResultConfig resultConfig, Map extraContext)  throws  Exception {
    37.         String resultClassName = resultConfig.getClassName();
    38.          if  (resultClassName ==  null )
    39.              return   null ;
    40.          //创建Result,因为Result是有状态的,所以每次请求都新建一个
    41.         Object result = buildBean(resultClassName, extraContext);
    42.         reflectionProvider.setProperties(resultConfig.getParams(), result, extraContext);
    43.          if  (result  instanceof  Result)
    44.              return  (Result) result;
    45.          throw   new  ConfigurationException(result.getClass().getName() +  " does not implement Result." );
    46.     }

        最后的时序图我拷贝开头url里那位作者的图吧。
    分享到:
    评论

    相关推荐

      struts2源代码 struts2源代码

      struts2源代码 正宗的 源码struts2源代码 正宗的 源码struts2源代码 正宗的 源码struts2源代码 正宗的 源码

      struts2.3.4源代码

      尽管描述中提到不包含XWork源代码,但XWork是Struts2的基础,它处理Action的执行和异常管理。 在Struts2.3.4源代码中,我们可以深入理解以下关键知识点: 1. **FilterDispatcher**: 这是Struts2框架的入口点,负责...

      struts2源代码分析

      在分析Struts2的源代码之前,你需要首先获取Struts2的源代码,可以通过访问http://www.opensymphony.com/xwork/download.action下载XWork的源码,因为它构成了Struts2的核心。下载的源代码压缩包名为struts-2.1.0-...

      Struts2源代码项目

      通过对这些源代码的阅读和分析,你可以了解Struts2如何处理HTTP请求,如何调度Action,以及它如何与Spring、Hibernate等其他框架集成。 `.settings`目录包含了Eclipse项目的特定配置,比如代码格式化规则、编译器...

      struts2 项目源代码

      这个"北大青鸟 struts2 项目源代码"是学习和理解Struts2框架的一个实用资源,尤其适合初学者和开发者深入研究。 在Struts2框架中,核心组件包括Action、Result、Interceptor(拦截器)、配置文件等。Action是业务...

      Struts2框架源码

      在MyEclipse9中,你可以导入这些源码,通过调试和阅读代码,理解Struts2的工作原理。对于初学者来说,这是一条深入理解MVC框架的好途径。你可以逐步分析Action类如何被调用,拦截器如何影响Action的执行流程,以及...

      JAVAEE源代码以及struts2源代码

      JavaEE源代码与Struts2源代码是JavaWeb开发中的重要组成部分,对于深入理解Web应用程序的构建和运行机制至关重要。JavaEE(Java Platform, Enterprise Edition)是Java平台的一个版本,专为开发和部署企业级应用而...

      struts2 源码分析

      从 org.apache.struts2.dispatcher.FilterDispatcher 开始 Java 代码阅读,我们可以看到 FilterDispatcher 的 init 方法,它负责初始化 Dispatcher 对象,并创建了一个 ActionMapper 实例,以便对请求进行处理。...

      struts2源码分析

      struts2源码详细解析51CTO下载-struts2源代码分析(个人觉得非常经典)

      struts2教程源代码

      在"struts2教程源代码"中,你可以找到一系列用于学习和实践Struts2框架的实例。这些源代码是针对初学者设计的,旨在帮助理解如何在实际应用中运用Struts2的核心概念和特性。"strut2课程源代码第一天及说明"可能包含...

      struts1.3.10源代码

      在Struts 1.3.10的源代码中,我们可以关注以下几个核心组件和知识点: 1. **ActionServlet**:这是Struts的核心控制器,负责处理来自客户端的HTTP请求。它实现了Servlet接口,并在web.xml中被配置为过滤所有与...

      Struts2源码分析

      在深入理解Struts2的工作原理时,源码分析是必不可少的步骤。Struts2的核心设计理念和设计模式相比Struts1.x有了显著的变化,这使得它成为一个独立且成熟的框架。 首先,Struts2的架构基于WebWork的核心,这意味着...

      struts2 源码解读

      通过阅读源码,我们可以了解到Struts2如何处理Action的请求映射、拦截器的执行逻辑、结果的渲染等细节。此外,还可以深入到动态方法调用、类型转换、异常处理等方面,这些都是Struts2处理请求和响应时的重要环节。 ...

      最新Struts2开源实例代码以及Struts2源码

      这份"最新Struts2开源实例代码以及Struts2源码"包含了Struts2框架的最新版本2.3.12的应用示例和源码,对于深入理解Struts2的工作机制和开发实践非常有帮助。 首先,我们来看`struts-2.3.12-apps.gz`,这个文件很...

      struts2文件上传下载源代码

      这篇博客文章提供的"struts2文件上传下载源代码"旨在帮助开发者理解和实现这些功能。 文件上传功能允许用户从他们的设备上传文件到服务器。在Struts2中,这通常通过表单实现,表单包含一个`&lt;input type="file"&gt;`...

      Struts2源代码与源码解析文档

      通过深入阅读"struts2源代码分析(个人觉得非常经典).doc"、"struts2源代码分析.docx"和解压后的"struts2源代码.rar",你可以获得Struts2框架的全面理解,从而更好地利用这个框架进行Web应用的开发和维护。同时,源码...

      struts2 源码

      深入学习Struts2的源码,有助于理解其运行机制,从而更好地优化代码、调试问题,甚至开发自己的扩展。对于Java Web开发者来说,掌握Struts2的基本原理和使用技巧,能够显著提高开发效率和应用质量。

    Global site tag (gtag.js) - Google Analytics