`
talentkep
  • 浏览: 101449 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

struts 核心解析

    博客分类:
阅读更多

 一、概述

     Struts2的核心是一个Filter,Action可以脱离web容器,那么是什么让http请求和action关联在一起的,下面我们深入源码来分析下Struts2是如何工作的。

FilterDispatcher API 写道
Deprecated. Since Struts 2.1.3, use StrutsPrepareAndExecuteFilter instead or StrutsPrepareFilter and StrutsExecuteFilter if needing using the ActionContextCleanUp filter in addition to this one

 

     鉴于常规情况官方推荐使用StrutsPrepareAndExecuteFilter替代FilterDispatcher,我们此文 将剖析StrutsPrepareAndExecuteFilter,其在工程中作为一个Filter配置在web.xml中,配置如下:

Xml代码
  1. < filter >   
  2.     < filter-name > struts2 </ filter-name >   
  3.     < filter-class > org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </ filter-class >   
  4. </ filter >   
  5. < filter-mapping >   
  6.     < filter-name > struts2 </ filter-name >   
  7.     < url-pattern > /* </ url-pattern >   
  8. </ filter-mapping >   
<filter>
	<filter-name>struts2</filter-name>
	<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>struts2</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

 

二、源码属性方法简介

    下面我们研究下StrutsPrepareAndExecuteFilter源码,类的主要信息如下:

 

属性摘要
protected  List <Pattern > excludedPatterns
           
protected  ExecuteOperations execute
           
protected  PrepareOperations prepare
           

 

    StrutsPrepareAndExecuteFilter与普通的Filter并无区别,方法除继承自Filter外,仅有一个回调方法,第三部分我 们将按照Filter方法调用顺序,由init—>doFilter—>destroy顺序地分析源码。

方法摘要
 void destroy ()
           继承自Filter,用于资源释放
 void doFilter (ServletRequest  req, ServletResponse  res, FilterChain  chain)  
           继承自Filter,执行方法
 void init (FilterConfig  filterConfig)  
           继承自Filter,初始化参数
protected  void postInit (Dispatcher  dispatcher, FilterConfig  filterConfig)
          Callback for post initialization(一个空的方法,用于方法回调初始化)

 

三、源码剖析    

 

    1、init方法

         init是Filter第一个运行的方法,我们看下struts2的核心Filter在调用init方法初始化时做哪些工作:

Java代码
  1.   public   void  init(FilterConfig filterConfig)  throws  ServletException {  
  2.         InitOperations init = new  InitOperations();  
  3.         try  {  
  4. //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中   
  5.             FilterHostConfig config = new  FilterHostConfig(filterConfig);  
  6. // 初始化struts内部日志   
  7.            init.initLogging(config);  
  8. //<strong>创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源</strong>   
  9.             Dispatcher dispatcher = init.initDispatcher(config);  
  10.             init.initStaticContentLoader(config, dispatcher);  
  11. //初始化类属性:prepare 、execute    
  12.             prepare = new  PrepareOperations(filterConfig.getServletContext(), dispatcher);  
  13.             execute = new  ExecuteOperations(filterConfig.getServletContext(), dispatcher);  
  14.             this .excludedPatterns = init.buildExcludedPatternsList(dispatcher);  
  15. //回调空的postInit方法   
  16.             postInit(dispatcher, filterConfig);  
  17.         } finally  {  
  18.             init.cleanup();  
  19.         }  
  20.  }  
 public void init(FilterConfig filterConfig) throws ServletException {
        InitOperations init = new InitOperations();
        try {
//封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中
            FilterHostConfig config = new FilterHostConfig(filterConfig);
// 初始化struts内部日志
           init.initLogging(config);
//创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源

            Dispatcher dispatcher = init.initDispatcher(config);
            init.initStaticContentLoader(config, dispatcher);
//初始化类属性:prepare 、execute 
            prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
            execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
			this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
//回调空的postInit方法
            postInit(dispatcher, filterConfig);
        } finally {
            init.cleanup();
        }
 }

 

   首先看下FilterHostConfig ,源码如下:

 

Java代码
  1. public   class  FilterHostConfig  implements  HostConfig {  
  2.   
  3.     private  FilterConfig config;  
  4.     /**  
  5.      *构造函数    
  6.      */       
  7.     public  FilterHostConfig(FilterConfig config) {  
  8.         this .config = config;  
  9.     }  
  10.     /**  
  11.      *  根据init-param配置的param-name获取param-value的值  
  12.      */     
  13.     public  String getInitParameter(String key) {  
  14.         return  config.getInitParameter(key);  
  15.     }  
  16.        /**  
  17.          *  返回初始化参数名的List  
  18.      */    
  19.     public  Iterator<String> getInitParameterNames() {  
  20.         return  MakeIterator.convert(config.getInitParameterNames());  
  21.     }  
  22.   
  23.     public  ServletContext getServletContext() {  
  24.         return  config.getServletContext();  
  25.     }  
  26. }  
public class FilterHostConfig implements HostConfig {

    private FilterConfig config;
    /**
     *构造函数  
     */    
    public FilterHostConfig(FilterConfig config) {
        this.config = config;
    }
    /**
     *  根据init-param配置的param-name获取param-value的值
     */  
    public String getInitParameter(String key) {
        return config.getInitParameter(key);
    }
       /**
         *  返回初始化参数名的List
     */ 
    public Iterator<String> getInitParameterNames() {
        return MakeIterator.convert(config.getInitParameterNames());
    }

    public ServletContext getServletContext() {
        return config.getServletContext();
    }
}

   只有短短的几行代码,getInitParameterNames是这个类的核心,将Filter初始化参数名称有枚举类型转为Iterator。此类的主要作为是对filterConfig 封装。

 

 

    重点来了,创建并初始化Dispatcher      

Java代码
  1. public  Dispatcher initDispatcher( HostConfig filterConfig ) {  
  2.        Dispatcher dispatcher = createDispatcher(filterConfig);  
  3.        dispatcher.init();  
  4.        return  dispatcher;  
  5.    }  
 public Dispatcher initDispatcher( HostConfig filterConfig ) {
        Dispatcher dispatcher = createDispatcher(filterConfig);
        dispatcher.init();
        return dispatcher;
    }

     创建Dispatcher,会读取 filterConfig 中的配置信息,将配置信息解析出来,封装成为一个Map,然后根绝servlet上下文和参数Map构造Dispatcher :

Java代码
  1. private  Dispatcher createDispatcher( HostConfig filterConfig ) {  
  2.         Map<String, String> params = new  HashMap<String, String>();  
  3.         for  ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {  
  4.             String name = (String) e.next();  
  5.             String value = filterConfig.getInitParameter(name);  
  6.             params.put(name, value);  
  7.         }  
  8.         return   new  Dispatcher(filterConfig.getServletContext(), params);  
  9.     }  
private Dispatcher createDispatcher( HostConfig filterConfig ) {
        Map<String, String> params = new HashMap<String, String>();
        for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {
            String name = (String) e.next();
            String value = filterConfig.getInitParameter(name);
            params.put(name, value);
        }
        return new Dispatcher(filterConfig.getServletContext(), params);
    }

  Dispatcher初始化,加载struts2的相关配置文件,将按照顺序逐一加载:default.properties,struts-default.xml,struts-plugin.xml,struts.xml,……

 

Java代码
  1. /**  
  2. *初始化过程中依次加载如下配置文件  
  3. */   
  4. public   void  init() {  
  5.   
  6.         if  (configurationManager ==  null ) {  
  7.             configurationManager = new  ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);  
  8.         }  
  9.   
  10.         try  {  
  11.             //加载org/apache/struts2/default.properties   
  12.             init_DefaultProperties(); // [1]   
  13.            //加载struts-default.xml,struts-plugin.xml,struts.xml   
  14.             init_TraditionalXmlConfigurations(); // [2]   
  15.             init_LegacyStrutsProperties(); // [3]   
  16.            //用户自己实现的ConfigurationProviders类               
  17.         init_CustomConfigurationProviders(); // [5]   
  18.             //Filter的初始化参数   
  19.         init_FilterInitParameters() ; // [6]   
  20.             init_AliasStandardObjects() ; // [7]   
  21.   
  22.             Container container = init_PreloadConfiguration();  
  23.             container.inject(this );  
  24.             init_CheckConfigurationReloading(container);  
  25.             init_CheckWebLogicWorkaround(container);  
  26.   
  27.             if  (!dispatcherListeners.isEmpty()) {  
  28.                 for  (DispatcherListener l : dispatcherListeners) {  
  29.                     l.dispatcherInitialized(this );  
  30.                 }  
  31.             }  
  32.         } catch  (Exception ex) {  
  33.             if  (LOG.isErrorEnabled())  
  34.                 LOG.error("Dispatcher initialization failed" , ex);  
  35.             throw   new  StrutsException(ex);  
  36.         }  
  37.     }  
/**
*初始化过程中依次加载如下配置文件
*/
public void init() {

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

        try {
            //加载org/apache/struts2/default.properties
            init_DefaultProperties(); // [1]
           //加载struts-default.xml,struts-plugin.xml,struts.xml
            init_TraditionalXmlConfigurations(); // [2]
            init_LegacyStrutsProperties(); // [3]
           //用户自己实现的ConfigurationProviders类            
        init_CustomConfigurationProviders(); // [5]
            //Filter的初始化参数
        init_FilterInitParameters() ; // [6]
            init_AliasStandardObjects() ; // [7]

            Container container = init_PreloadConfiguration();
            container.inject(this);
            init_CheckConfigurationReloading(container);
            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);
        }
    }

 

   初始化default.properties,具体的初始化操作在DefaultPropertiesProvider类中

  

Java代码
  1. private   void  init_DefaultProperties() {  
  2.        configurationManager.addConfigurationProvider(new  DefaultPropertiesProvider());  
  3.    }  
 private void init_DefaultProperties() {
        configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
    }

    

   下面我们看下DefaultPropertiesProvider类源码:

 

Java代码
  1. public   void  register(ContainerBuilder builder, LocatableProperties props)  
  2.             throws  ConfigurationException {  
  3.           
  4.         Settings defaultSettings = null ;  
  5.         try  {  
  6.             defaultSettings = new  PropertiesSettings( "org/apache/struts2/default" );  
  7.         } catch  (Exception e) {  
  8.             throw   new  ConfigurationException( "Could not find or error in org/apache/struts2/default.properties" , e);  
  9.         }  
  10.           
  11.         loadSettings(props, defaultSettings);  
  12.     }  
public void register(ContainerBuilder builder, LocatableProperties props)
            throws ConfigurationException {
        
        Settings defaultSettings = null;
        try {
            defaultSettings = new PropertiesSettings("org/apache/struts2/default");
        } catch (Exception e) {
            throw new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", e);
        }
        
        loadSettings(props, defaultSettings);
    }

 

   其他的我们再次省略,大家可以浏览下各个初始化操作都加载了那些文件


3、doFilter方法

     doFilter是过滤器的执行方法,它拦截提交的HttpServletRequest请求,HttpServletResponse响应,作为strtus2的核心拦截器,在doFilter里面到底做了哪些工作,我们将逐行解读其源码,源码如下:

 

Java代码
  1.   public   void  doFilter(ServletRequest req, ServletResponse res, FilterChain chain)  throws  IOException, ServletException {  
  2.      //父类向子类转:强转为http请求、响应   
  3.      HttpServletRequest request = (HttpServletRequest) req;  
  4.      HttpServletResponse response = (HttpServletResponse) res;  
  5.   
  6.      try  {  
  7.          //设置编码和国际化   
  8.          prepare.setEncodingAndLocale(request, response);  
  9.           //创建Action上下文(重点)   
  10.          prepare.createActionContext(request, response);  
  11.          prepare.assignDispatcherToThread();  
  12. if  ( excludedPatterns !=  null  && prepare.isUrlExcluded(request, excludedPatterns)) {  
  13.     chain.doFilter(request, response);  
  14. else  {  
  15.     request = prepare.wrapRequest(request);  
  16.     ActionMapping mapping = prepare.findActionMapping(request, response, true );  
  17.     if  (mapping ==  null ) {  
  18.         boolean  handled = execute.executeStaticResourceRequest(request, response);  
  19.         if  (!handled) {  
  20.             chain.doFilter(request, response);  
  21.         }  
  22.     } else  {  
  23.         execute.executeAction(request, response, mapping);  
  24.     }  
  25. }  
  26.      } finally  {  
  27.          prepare.cleanupRequest(request);  
  28.      }  
  29.  }  
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        //父类向子类转:强转为http请求、响应
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {
            //设置编码和国际化
            prepare.setEncodingAndLocale(request, response);
             //创建Action上下文(重点)
            prepare.createActionContext(request, response);
            prepare.assignDispatcherToThread();
			if ( excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
				chain.doFilter(request, response);
			} else {
				request = prepare.wrapRequest(request);
				ActionMapping mapping = prepare.findActionMapping(request, response, true);
				if (mapping == null) {
					boolean handled = execute.executeStaticResourceRequest(request, response);
					if (!handled) {
						chain.doFilter(request, response);
					}
				} else {
					execute.executeAction(request, response, mapping);
				}
			}
        } finally {
            prepare.cleanupRequest(request);
        }
    }

 

    setEncodingAndLocale调用了dispatcher方法的prepare方法:

 

Java代码
  1. /**  
  2.      * Sets the request encoding and locale on the response  
  3.      */   
  4.     public   void  setEncodingAndLocale(HttpServletRequest request, HttpServletResponse response) {  
  5.         dispatcher.prepare(request, response);  
  6.     }  
/**
     * Sets the request encoding and locale on the response
     */
    public void setEncodingAndLocale(HttpServletRequest request, HttpServletResponse response) {
        dispatcher.prepare(request, response);
    }

 

   下面我们看下prepare方法,这个方法很简单只是设置了encoding 、locale ,做的只是一些辅助的工作:

Java代码
  1. public   void  prepare(HttpServletRequest request, HttpServletResponse response) {  
  2.         String encoding = null ;  
  3.         if  (defaultEncoding !=  null ) {  
  4.             encoding = defaultEncoding;  
  5.         }  
  6.   
  7.         Locale locale = null ;  
  8.         if  (defaultLocale !=  null ) {  
  9.             locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());  
  10.         }  
  11.   
  12.         if  (encoding !=  null ) {  
  13.             try  {  
  14.                 request.setCharacterEncoding(encoding);  
  15.             } catch  (Exception e) {  
  16.                 LOG.error("Error setting character encoding to '"  + encoding +  "' - ignoring." , e);  
  17.             }  
  18.         }  
  19.   
  20.         if  (locale !=  null ) {  
  21.             response.setLocale(locale);  
  22.         }  
  23.   
  24.         if  (paramsWorkaroundEnabled) {  
  25.             request.getParameter("foo" );  // simply read any parameter (existing or not) to "prime" the request   
  26.         }  
  27.     }  
public void prepare(HttpServletRequest request, HttpServletResponse response) {
        String encoding = null;
        if (defaultEncoding != null) {
            encoding = defaultEncoding;
        }

        Locale locale = null;
        if (defaultLocale != null) {
            locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale());
        }

        if (encoding != null) {
            try {
                request.setCharacterEncoding(encoding);
            } catch (Exception e) {
                LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);
            }
        }

        if (locale != null) {
            response.setLocale(locale);
        }

        if (paramsWorkaroundEnabled) {
            request.getParameter("foo"); // simply read any parameter (existing or not) to "prime" the request
        }
    }

 

   Action上下文创建(重点)

       ActionContext是一个容器,这个容易主要存储request、session、application、parameters等相关信 息.ActionContext是一个线程的本地变量,这意味着不同的action之间不会共享ActionContext,所以也不用考虑线程安全问 题。其实质是一个Map,key是标示request、session、……的字符串,值是其对应的对象:

Java代码
  1. static  ThreadLocal actionContext =  new  ThreadLocal();  
  2. Map<String, Object> context;  
static ThreadLocal actionContext = new ThreadLocal();
Map<String, Object> context;

 
   下面我们看下如何创建action上下文的,代码如下:

 

Java代码
  1. /**  
  2. *创建Action上下文,初始化thread local  
  3. */   
  4. public  ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {  
  5.     ActionContext ctx;  
  6.     Integer counter = 1 ;  
  7.     Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);  
  8.     if  (oldCounter !=  null ) {  
  9.         counter = oldCounter + 1 ;  
  10.     }  
  11.     //注意此处是从ThreadLocal中获取此ActionContext变量   
  12.     ActionContext oldContext = ActionContext.getContext();  
  13.     if  (oldContext !=  null ) {  
  14.         // detected existing context, so we are probably in a forward   
  15.         ctx = new  ActionContext( new  HashMap<String, Object>(oldContext.getContextMap()));  
  16.     } else  {  
  17.         ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class ).createValueStack();  
  18.         stack.getContext().putAll(dispatcher.createContextMap(request, response, null , servletContext));  
  19.         //stack.getContext()返回的是一个Map<String,Object>,根据此Map构造一个ActionContext   
  20.         ctx = new  ActionContext(stack.getContext());  
  21.     }  
  22.     request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);  
  23.     //将ActionContext存如ThreadLocal   
  24.     ActionContext.setContext(ctx);  
  25.     return  ctx;  
  26. }  
/**
*创建Action上下文,初始化thread local
*/
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
    ActionContext ctx;
    Integer counter = 1;
    Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
    if (oldCounter != null) {
        counter = oldCounter + 1;
    }
    //注意此处是从ThreadLocal中获取此ActionContext变量
    ActionContext oldContext = ActionContext.getContext();
    if (oldContext != null) {
        // detected existing context, so we are probably in a forward
        ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
    } else {
        ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
        stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
        //stack.getContext()返回的是一个Map<String,Object>,根据此Map构造一个ActionContext
        ctx = new ActionContext(stack.getContext());
    }
    request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
    //将ActionContext存如ThreadLocal
    ActionContext.setContext(ctx);
    return ctx;
}

 

    上面代码中dispatcher.createContextMap,如何封装相关参数:

 

Java代码
  1. public  Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,  
  2.             ActionMapping mapping, ServletContext context) {  
  3.   
  4.         // request map wrapping the http request objects   
  5.         Map requestMap = new  RequestMap(request);  
  6.   
  7.         // parameters map wrapping the http parameters.  ActionMapping parameters are now handled and applied separately   
  8.         Map params = new  HashMap(request.getParameterMap());  
  9.   
  10.         // session map wrapping the http session   
  11.         Map session = new  SessionMap(request);  
  12.   
  13.         // application map wrapping the ServletContext   
  14.         Map application = new  ApplicationMap(context);  
  15.                 //requestMap、params、session等Map封装成为一个上下文Map,逐个调用了map.put(Map p).   
  16.         Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);  
  17.   
  18.         if  (mapping !=  null ) {  
  19.             extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);  
  20.         }  
  21.         return  extraContext;  
  22. }  
public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
            ActionMapping mapping, ServletContext context) {

        // request map wrapping the http request objects
        Map requestMap = new RequestMap(request);

        // parameters map wrapping the http parameters.  ActionMapping parameters are now handled and applied separately
        Map params = new HashMap(request.getParameterMap());

        // session map wrapping the http session
        Map session = new SessionMap(request);

        // application map wrapping the ServletContext
        Map application = new ApplicationMap(context);
				//requestMap、params、session等Map封装成为一个上下文Map,逐个调用了map.put(Map p).
        Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response, context);

        if (mapping != null) {
            extraContext.put(ServletActionContext.ACTION_MAPPING, mapping);
        }
        return extraContext;
}

 

 我们简单看下RequestMap,其他的省略。RequestMap类实现了抽象Map,故其本身是一个Map,主要方法实现:

Java代码
  1. //map的get实现   
  2. public  Object get(Object key) {  
  3.     return  request.getAttribute(key.toString());  
  4. }  
  5. //map的put实现   
  6. public  Object put(Object key, Object value) {  
  7.     Object oldValue = get(key);  
  8.     entries = null ;  
  9.     request.setAttribute(key.toString(), value);  
  10.     return  oldValue;  
  11. }  
//map的get实现
public Object get(Object key) {
    return request.getAttribute(key.toString());
}
//map的put实现
public Object put(Object key, Object value) {
    Object oldValue = get(key);
    entries = null;
    request.setAttribute(key.toString(), value);
    return oldValue;
}

 

   下面是源码展示了如何执行Action控制器:

 

Java代码
  1. public   void  executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)  throws  ServletException {  
  2.     dispatcher.serviceAction(request, response, servletContext, mapping);  
  3. }  
  4.   
  5.     public   void  serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,  
  6.                               ActionMapping mapping) throws  ServletException {  
  7.                 //封装执行的上下文环境,主要讲相关信息存储入map   
  8.         Map<String, Object> extraContext = createContextMap(request, response, mapping, context);  
  9.   
  10.         // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action   
  11.         ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);  
  12.         boolean  nullStack = stack ==  null ;  
  13.         if  (nullStack) {  
  14.             ActionContext ctx = ActionContext.getContext();  
  15.             if  (ctx !=  null ) {  
  16.                 stack = ctx.getValueStack();  
  17.             }  
  18.         }  
  19.         if  (stack !=  null ) {  
  20.             extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));  
  21.         }  
  22.   
  23.         String timerKey = "Handling request from Dispatcher" ;  
  24.         try  {  
  25.             UtilTimerStack.push(timerKey);  
  26.             //获取命名空间   
  27.             String namespace = mapping.getNamespace();  
  28.             //获取action配置的name属性   
  29.             String name = mapping.getName();  
  30.             //获取action配置的method属性   
  31.             String method = mapping.getMethod();  
  32.   
  33.             Configuration config = configurationManager.getConfiguration();  
  34.             //根据执行上下文参数,命名空间,名称等创建用户自定义Action的代理对象   
  35.             ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class ).createActionProxy(  
  36.                     namespace, name, method, extraContext, true false );  
  37.   
  38.             request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());  
  39.   
  40.             // if the ActionMapping says to go straight to a result, do it!   
  41.                     //执行execute方法,并转向结果   
  42.             if  (mapping.getResult() !=  null ) {  
  43.                 Result result = mapping.getResult();  
  44.                 result.execute(proxy.getInvocation());  
  45.             } else  {  
  46.                 proxy.execute();  
  47.             }  
  48.   
  49.             // If there was a previous value stack then set it back onto the request   
  50.             if  (!nullStack) {  
  51.                 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);  
  52.             }  
  53.         } catch  (ConfigurationException e) {  
  54.             // WW-2874 Only log error if in devMode   
  55.             if (devMode) {  
  56.                 String reqStr = request.getRequestURI();  
  57.                 if  (request.getQueryString() !=  null ) {  
  58.                     reqStr = reqStr + "?"  + request.getQueryString();  
  59.                 }  
  60.                 LOG.error("Could not find action or result\n"  + reqStr, e);  
  61.             }  
  62.             else  {  
  63.                 LOG.warn("Could not find action or result" , e);  
  64.             }  
  65.             sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);  
  66.         } catch  (Exception e) {  
  67.             sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);  
  68.         } finally  {  
  69.             UtilTimerStack.pop(timerKey);  
  70.         }  
  71.     }  
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
    dispatcher.serviceAction(request, response, servletContext, mapping);
}

    public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
                              ActionMapping mapping) throws ServletException {
				//封装执行的上下文环境,主要讲相关信息存储入map
        Map<String, Object> extraContext = createContextMap(request, response, mapping, context);

        // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
        ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
        boolean nullStack = stack == null;
        if (nullStack) {
            ActionContext ctx = ActionContext.getContext();
            if (ctx != null) {
                stack = ctx.getValueStack();
            }
        }
        if (stack != null) {
            extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));
        }

        String timerKey = "Handling request from Dispatcher";
        try {
            UtilTimerStack.push(timerKey);
            //获取命名空间
            String namespace = mapping.getNamespace();
            //获取action配置的name属性
            String name = mapping.getName();
            //获取action配置的method属性
            String method = mapping.getMethod();

            Configuration config = configurationManager.getConfiguration();
            //根据执行上下文参数,命名空间,名称等创建用户自定义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!
    				//执行execute方法,并转向结果
            if (mapping.getResult() != null) {
                Result result = mapping.getResult();
                result.execute(proxy.getInvocation());
            } else {
                proxy.execute();
            }

            // If there was a previous value stack then set it back onto the request
            if (!nullStack) {
                request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
            }
        } catch (ConfigurationException e) {
        	// WW-2874 Only log error if in devMode
        	if(devMode) {
                String reqStr = request.getRequestURI();
                if (request.getQueryString() != null) {
                    reqStr = reqStr + "?" + request.getQueryString();
                }
                LOG.error("Could not find action or result\n" + reqStr, e);
            }
        	else {
        		LOG.warn("Could not find action or result", e);
        	}
            sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);
        } catch (Exception e) {
            sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
        } finally {
            UtilTimerStack.pop(timerKey);
        }
    }

 

   文中对如何解析Struts.xml,如何将URL与action映射匹配为分析,有需要的我后续补全,因为 StrutsXmlConfigurationProvider继承XmlConfigurationProvider,并在register方法回调父 类的register,有兴趣的可以深入阅读下下XmlConfigurationProvider源码:

 

Java代码
  1. public   void  register(ContainerBuilder containerBuilder, LocatableProperties props)  throws  ConfigurationException {  
  2.        if  (servletContext !=  null  && !containerBuilder.contains(ServletContext. class )) {  
  3.            containerBuilder.factory(ServletContext.class new  Factory<ServletContext>() {  
  4.                public  ServletContext create(Context context)  throws  Exception {  
  5.                    return  servletContext;  
  6.                }  
  7.            });  
  8.        }  
  9.        //调用父类的register,关键点所在   
  10.        super .register(containerBuilder, props);  
  11.    }  
 public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
        if (servletContext != null && !containerBuilder.contains(ServletContext.class)) {
            containerBuilder.factory(ServletContext.class, new Factory<ServletContext>() {
                public ServletContext create(Context context) throws Exception {
                    return servletContext;
                }
            });
        }
        //调用父类的register,关键点所在
        super.register(containerBuilder, props);
    }

 

 

     struts2-core-2.2.1.jar包中struts-2.1.7.dtd对于Action的定义如下:

Xml代码
  1. <!ELEMENT action (param|result|interceptor-ref|exception-mapping)* >   
  2. <!ATTLIST action  
  3.     name CDATA #REQUIRED  
  4.     class CDATA #IMPLIED  
  5.     method CDATA #IMPLIED  
  6.     converter CDATA #IMPLIED  
  7. >   
<!ELEMENT action (param|result|interceptor-ref|exception-mapping)*>
<!ATTLIST action
    name CDATA #REQUIRED
    class CDATA #IMPLIED
    method CDATA #IMPLIED
    converter CDATA #IMPLIED
>

    从上述DTD中可见Action元素可以含有name 、class 、method 、converter 属性。

 

   XmlConfigurationProvider解析struts.xml配置的Action元素:

Java代码
  1. protected  
    分享到:
    评论

相关推荐

    Struts2核心解析(上).ppt

    Struts2核心解析PPT,学习STRUTS2的最好课程资料

    Struts2核心解析(下).

    Struts2核心解析(下).struts2学习的最好课程资料

    struts2核心解析

    在本文中,我们将全面解析Struts2的核心组件、工作原理以及它如何简化MVC(模型-视图-控制器)架构的开发。 1. **Action与ActionMapping** Struts2的核心在于Action类,它是业务逻辑处理的主要载体。每个Action...

    struts2解析文件

    - **Action类**: Struts2的核心是Action类,它是业务逻辑的载体。开发者通常会创建一个Action类来处理用户请求,并通过execute方法执行相应的业务逻辑。 - **配置文件**: Struts2的配置文件通常包括struts.xml,...

    struts核心的jar(只是struts运行所需的核心jar)

    1. **`struts2-core.jar`**:这是Struts 2框架的核心库,包含了Action、Result、Interceptor等核心接口和实现类,以及配置解析、请求处理等相关功能。这个jar文件是构建任何基于Struts 2的应用的基础。 2. **`xwork...

    struts2核心文件

    7. **FilterDispatcher(或StrutsPrepareAndExecuteFilter)**: 这是Struts2的前端控制器,负责接收HTTP请求,解析请求参数,并根据配置文件调度Action。 8. **Tiles2**: Struts2集成了Tiles2框架,用于构建复杂的...

    Struts2 核心jar包源码

    Struts2的核心jar包是框架运行的基础,包含了处理请求、控制流程、数据绑定、异常处理等关键功能。源码分析对于理解其工作原理、进行定制化开发和优化性能具有重要意义。 首先,我们来看`xwork`,它是Struts2的核心...

    Struts2 技术内幕——深入解析Struts2架构设计与实现原理

    ### Struts2技术内幕——深入解析Struts2架构设计与实现原理 #### 一、Struts2概述 Struts2是Struts框架的第二代版本,它是在Struts1的基础上进行了大量的改进和完善后诞生的。Struts2不仅继承了Struts1的核心思想...

    简单易懂Struts核心讲解

    1. **Struts核心流程** Struts的核心流程始于客户端发送HTTP请求到服务器。这个请求被Struts的前端控制器——`ActionServlet`捕获。`ActionServlet`根据配置文件(struts-config.xml)解析请求,确定对应的Action。...

    struts2核心包

    标题中的"struts2核心包"指的是Struts2框架的核心组件,这些组件构成了框架的基础,使得开发者能够构建高效、可维护的Web应用。下面将详细阐述这些核心包的作用和功能。 1. **xwork-core-2.1.6.jar**: 这是XWork...

    Struts2框架核心jar包

    - Struts2根据`struts.xml`配置文件解析请求,找到对应的Action。 - 拦截器链执行,每个拦截器按照配置顺序执行其逻辑。 - Action被执行,完成业务逻辑。 - Action返回一个Result,Struts2根据Result类型决定...

    struts2源码解析.pdf

    在"struts2源码解析.pdf"文档中,主要探讨了以下几个关键组件及其功能: 1. **ActionContext**: - `ActionContext`是Struts2的核心上下文,它存储了与当前Action执行相关的所有信息,如请求参数、session数据等。...

    Struts-Action核心代码

    1. **初始化配置**:在Servlet容器启动时,ActionServlet会加载并解析`struts-config.xml`配置文件,获取所有Action配置信息,包括Action的映射、Form Bean定义、数据源等。 2. **请求分发**:当接收到HTTP请求时,...

    Struts2核心包

    6. **工作流(Workflow)**:Struts2的工作流组件负责解析用户的请求,找到相应的Action并执行。这个过程涉及到`com.opensymphony.xwork2.DefaultActionProxy`和`com.opensymphony.xwork2.DefaultActionInvocation`...

    Struts2 技术内幕-深入解析Struts2架构设计与实现原理

    《Struts2技术内幕:深入解析Struts2架构设计与实现原理》以Struts2的源代码为依托,通过对Struts2的源代码的全面剖析深入探讨了Struts2的架构设计、实现原理、设计理念与设计哲学,对从宏观上和微观上去了解Struts2...

    struts2 原理 解析 图

    `struts原理.txt`文件可能包含了文字描述,进一步解释了Struts2的核心概念和机制,比如Action的配置、结果映射、拦截器的实现方式,以及Struts2如何整合其他技术,如Spring或Hibernate进行依赖注入和持久化操作。...

    Struts1源码解析

    Struts1是一个经典的Java Web框架,它以MVC(Model-View-Controller)设计模式为核心,简化了Web应用的开发。本文将深入解析Struts1的源码,以帮助理解其内部工作原理。 首先,我们从ActionServlet的生命周期开始。...

    深入struts1核心思想.doc

    深入理解Struts1的核心思想对于掌握Web应用开发至关重要。以下将详细介绍Struts1中的关键组件及其工作原理。 1. **Digester框架**: Digester是Apache Commons库的一部分,主要用于XML文档的解析和转换。在Struts1...

    Struts2+技术内幕——深入解析Struts2架构设计与实现原理

    总之,《Struts2技术内幕——深入解析Struts2架构设计与实现原理》配合《struts2基础.chm》,将帮助读者全面掌握Struts2的架构设计、核心组件、配置方式、插件使用以及源码解读,对于想要在Java Web领域深入发展的...

    Struts2技术内幕 深入解析Struts架构设计与实现原理

    ### Struts2技术内幕:深入解析Struts架构设计与实现原理 #### Struts2概述 Struts2是Apache Software Foundation支持的一个开源项目,它是Struts1的下一代版本,继承了Struits1的优点,并在此基础上进行了大量的...

Global site tag (gtag.js) - Google Analytics