搜尋
首頁Javajava教程struts1之ActionServlet的實例詳解

struts1之ActionServlet的實例詳解

Sep 05, 2017 am 11:31 AM
詳解

這篇文章主要介紹了struts1之ActionServlet詳解,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

在web.xml中我們除了配置ActionServlet還配置了一些初始化參數信息,首先我們看第一個config參數,這裡配置的是/WEB-INF/struts -config.xml,因為要下面傳遞一個這樣一個配置訊息,這個xml檔名是struts1標準的名字,所以這裡這個初始化訊息完全可以刪除,如果不用這個標準名稱這裡就必須要在這裡配置。現在我們配置的是標準名字,所以我們可以刪除,這是為什麼呢?這裡要看ActionServlet原始碼才可以。

從圖片上我們可以看到ActionServlet中已經寫好了預設的config訊息了,就是標準名稱。所以這裡刪除也是可以的。
在看下面的debug和detail參數,這兩個參數資訊是有關日誌資訊層級的設置,主要關於解析設定檔/WEB-INF/struts-config.xml層級的初始化參數。這裡這兩個參數可以完全去掉也不影響。

最後還有一個load-on-startup配置,這個是初始化servlet層級的初始化訊息,這個參數如果大於等於0就是說明在伺服器一啟動就把servlet初始化,也就是呼叫ActionServlet的init方法,這個也可以到ActionServlet的原始碼中去找。

當ActionServlet初始化的時候就會讀取/WEB-INF/struts-config.xml資訊到記憶體中,讀到記憶體是以什麼樣的形式展現的呢?我們現在可以看一下以前部落格的那個mvc實例,那裡面讀取設定檔中的資訊是以Actionmapping的形式展現的。另外servlet-mapping的設定就不講解了,這都知道就是匹配url路徑的,當遇到url-pattern的路徑時候就會實例化Actionservlet。

透過這篇文章我們知道了當我們要求的時候ActionServlet是怎麼實例化的,也知道為什麼我們要設定web.xml資訊了。那我們為什麼要配置/WEB-INF/struts-config.xml文件,ActionServlet是如何傳遞請求的,如何和ActionForm、ActionMapping、Action等互動的最終完成使用者請求的呢?

我們先從ActionServlet原始碼的init方法開始。因為ActionServlet就是一個Servlet,它也是具有典型的那幾個方法init、doget、dopost等方法。既然是初始化,那我們就要看init方法。 Init方法的原始碼如下:


/** 
   * <p>Initialize this servlet. Most of the processing has been factored into 
   * support methods so that you can overrideparticular functionality at a 
   * fairly granular level.</p> 
   * 
   * @exception ServletException if we cannotconfigure ourselves correctly 
   */ 
  publicvoidinit() throwsServletException { 
  
    // Wraps the entire initialization in a try/catch tobetter handle 
    // unexpected exceptions and errors to provide better feedback 
    // to the developer 
    try { 
      initInternal(); 
      initOther(); 
      initServlet(); 
   
      getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this); 
      initModuleConfigFactory(); 
      // Initialize modules as needed 
      ModuleConfig moduleConfig =initModuleConfig("", config); 
      initModuleMessageResources(moduleConfig); 
      initModuleDataSources(moduleConfig); 
      initModulePlugIns(moduleConfig); 
      moduleConfig.freeze(); 
   
      Enumeration names =getServletConfig().getInitParameterNames(); 
      while (names.hasMoreElements()) { 
        String name = (String)namesnextElement(); 
        if (!name.startsWith("config/")) { 
          continue; 
        } 
        String prefix =name.substring(6); 
        moduleConfig = initModuleConfig 
          (prefix,getServletConfig().getInitParameter(name)); 
        initModuleMessageResources(moduleConfig); 
        initModuleDataSources(moduleConfig); 
        initModulePlugIns(moduleConfig); 
        moduleConfig.freeze(); 
      } 
   
      this.initModulePrefixes(this.getServletContext()); 
   
      thisdestroyConfigDigester(); 
    } catch (UnavailableException ex) { 
      throw ex; 
    } catch (Throwable t) { 
  
      // The follow error message is not retrieved from internal message 
      // resources as they may not have been able to have been 
      // initialized 
      logerror("Unable to initialize Struts ActionServlet due to an " 
        + "unexpected exception or error thrown, so marking the " 
        + "servlet as unavailable. Mostlikely, this is due to an " 
        + "incorrect or missing library dependency.", t); 
      throw new UnavailableException(t.getMessage()); 
    }   
}

在解釋這段程式碼的流程和意思之前,有必要說一句,就是當我們在eclipse裡面看程式碼的時候,尤其是看一段生疏的很長的程式碼的時候,希望能夠經常使用Ctrl鍵(多餘的不解釋)。

下面開始講解這段程式碼的流程和具體每一步的意義,如果有不正確的地方,希望指正。

首先映入眼簾的是initInternal()方法。這個方法的實作程式碼是:

程式碼段一:


#
/** 
   * <p>Initialize our internal MessageResourcesbundle</p> 
   * 
   * @exception ServletException if we cannotinitialize these resources 
   */ 
  protectedvoidinitInternal() throwsServletException { 
  
    // :FIXME: Document UnavailableException 
  
    try { 
      internal = MessageResourcesgetMessageResources(internalName); 
    } catch (MissingResourceException e) { 
      log.error("Cannot load internal resources from &#39;"+ internalName+ "&#39;", 
        e); 
      throw new UnavailableException 
        ("Cannot load internal resources from &#39;"+ internalName+ "&#39;"); 
    } 
  
}

程式碼片段二:


#
/** 
   * Create and return an instance of <code>MessageResources</code> for the 
   * created by the default <code>MessageResourcesFactory</code>. 
   * 
   * @param config Configuration parameterfor this message bundle. 
   */ 
  publicsynchronizedstaticMessageResources getMessageResources(String config) { 
  
    if (defaultFactory == null) { 
      defaultFactory =MessageResourcesFactory.createFactory(); 
    } 
  
    return defaultFactory.createResources(config); 
}

程式碼段三:


/** 
   * Create and return a <code>MessageResourcesFactory</code> instance ofthe 
   * appropriate class, which can be used tocreate customized 
   * <code>MessageResources</code>instances If no such factory can be 
   * created, return <code>null</code> instead 
   */ 
  publicstaticMessageResourcesFactory createFactory(){ 
  
    // Construct a new instance of the specified factory class 
    try { 
      if (clazz == null) 
        clazz = RequestUtils.applicationClass(factoryClass); 
      MessageResourcesFactory factory = 
        (MessageResourcesFactory) clazz.newInstance(); 
      return (factory); 
    } catch (Throwable t) { 
      LOG.error("MessageResourcesFactory.createFactory",t); 
      return (null); 
    } 
  
}

這個方法的具體作用就是初始化MessageResources,具體實作是工廠模式,首先判斷defaultFactory是否存在,不存在則建立工廠,defaultFactory = MessageResourcesFactory.createFactory(),在透過工廠建立資源類別defaultFactory.createResources(config);存在則直接建立資源類別。

initOther()的方法,主要是初始化其它的配置,取得我們自己的struts-config設定檔的路徑,而它的預設路徑就是web-inf/struts-config.xml,另外這個方法還會註冊一些轉換類別的。特定原始碼是:


/** 
   * <p>Initialize other global characteristics ofthe controller servlet</p> 
   * 
   * @exception ServletException if we cannotinitialize these resources 
   */ 
  protectedvoidinitOther() throwsServletException { 
  
    String value = null; 
    value =getServletConfig().getInitParameter("config"); 
    if (value != null) { 
      config = value; 
    } 
  
    // Backwards compatibility for form beans of Java wrapper classes 
    // Set to true for strict Struts 0 compatibility 
    value =getServletConfig().getInitParameter("convertNull"); 
    if ("true".equalsIgnoreCase(value) 
      || "yes".equalsIgnoreCase(value) 
      || "on".equalsIgnoreCase(value) 
      || "y".equalsIgnoreCase(value) 
      || "1".equalsIgnoreCase(value)) { 
  
      convertNull = true; 
    } 
  
    if (convertNull) { 
      ConvertUtils.deregister(); 
      ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class); 
      ConvertUtils.register(new BigIntegerConverter(null), BigInteger.class); 
      ConvertUtils.register(new BooleanConverter(null), Boolean.class); 
      ConvertUtils.register(new ByteConverter(null), Byte.class); 
      ConvertUtils.register(new CharacterConverter(null), Character.class); 
      ConvertUtils.register(new DoubleConverter(null), Double.class); 
      ConvertUtils.register(new FloatConverter(null), Float.class); 
      ConvertUtils.register(new IntegerConverter(null), Integer.class); 
      ConvertUtils.register(new LongConverter(null), Long.class); 
      ConvertUtils.register(new ShortConverter(null), Short.class); 
    } 
  
}

initServlet()方法是利用digester讀取web.xml檔案並且放到servletContext中。具體實作原始碼:


/** 
 * <p>Initialize the servlet mapping under which our controller servlet 
 * is being accessed. This will be used in the <code>&html:form></code> 
 * tag to generate correct destination URLs for form submissions.</p> 
 * 
 * @throws ServletException if error happens while scanning web.xml 
 */ 
protected void initServlet() throws ServletException { 
 
  // Remember our servlet name 
  this.servletName = getServletConfig().getServletName(); 
 
  // Prepare a Digester to scan the web application deployment descriptor 
  Digester digester = new Digester(); 
  digester.push(this); 
  digester.setNamespaceAware(true); 
  digester.setValidating(false); 
 
  // Register our local copy of the DTDs that we can find 
  for (int i = 0; i < registrations.length; i += 2) { 
    URL url = this.getClass().getResource(registrations[i+1]); 
    if (url != null) { 
      digester.register(registrations[i], url.toString()); 
    } 
  } 
 
  // Configure the processing rules that we need 
  digester.addCallMethod("web-app/servlet-mapping", 
              "addServletMapping", 2); 
  digester.addCallParam("web-app/servlet-mapping/servlet-name", 0); 
  digester.addCallParam("web-app/servlet-mapping/url-pattern", 1); 
 
  // Process the web application deployment descriptor 
  if (log.isDebugEnabled()) { 
    log.debug("Scanning web.xml for controller servlet mapping"); 
  } 
 
  InputStream input = 
    getServletContext().getResourceAsStream("/WEB-INF/web.xml"); 
 
  if (input == null) { 
    log.error(internal.getMessage("configWebXml")); 
    throw new ServletException(internal.getMessage("configWebXml")); 
  } 
 
  try { 
    digester.parse(input); 
 
  } catch (IOException e) { 
    log.error(internal.getMessage("configWebXml"), e); 
    throw new ServletException(e); 
 
  } catch (SAXException e) { 
    log.error(internal.getMessage("configWebXml"), e); 
    throw new ServletException(e); 
 
  } finally { 
    try { 
      input.close(); 
    } catch (IOException e) { 
      log.error(internal.getMessage("configWebXml"), e); 
      throw new ServletException(e); 
    } 
  } 
 
  // Record a servlet context attribute (if appropriate) 
  if (log.isDebugEnabled()) { 
    logdebug("Mapping for servlet &#39;" + servletName + "&#39; = &#39;" + 
      servletMapping + "&#39;"); 
  } 
 
  if (servletMapping != null) { 
    getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping); 
  } 
 
}

先說在說之前還是先講init方法的具體實作程式碼寫出來以便大家方便閱讀和理解。

Init原始碼:


public void init() throws ServletException { 
  
 try { 
    //初始化资源类 
   initInternal(); 
   //注册转换类 
   initOther(); 
   //利用digester读取webxml文件并且将其放到servletContext中 
   initServlet(); 
   getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this); 
    
   initModuleConfigFactory(); 
   ModuleConfig moduleConfig = initModuleConfig("", config); 
   initModuleMessageResources(moduleConfig); 
   initModuleDataSources(moduleConfig); 
   initModulePlugIns(moduleConfig); 
   moduleConfig.freeze(); 
 
   Enumeration names = getServletConfig().getInitParameterNames(); 
   while (names.hasMoreElements()) { 
     String name = (String) names.nextElement(); 
     if (!name.startsWith("config/")) { 
       continue; 
     } 
     String prefix = name.substring(6); 
     moduleConfig = initModuleConfig 
       (prefix, getServletConfig()getInitParameter(name)); 
     initModuleMessageResources(moduleConfig); 
     initModuleDataSources(moduleConfig); 
     initModulePlugIns(moduleConfig); 
     moduleConfig.freeze(); 
   } 
 
   this.initModulePrefixes(this.getServletContext()); 
 
   this.destroyConfigDigester(); 
 } catch (UnavailableException ex) { 
   throw ex; 
 } catch (Throwable t) { 
   log.error("Unable to initialize Struts ActionServlet due to an " 
     + "unexpected exception or error thrown, so marking the " 
     + "servlet as unavailable Most likely, this is due to an " 
     + "incorrect or missing library dependency", t); 
   throw new UnavailableException(t.getMessage()); 
 }   
}

getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY,this);這句話是將ActionServlet實例將以Globals.ACTION_SERVLET_KEY存入servletcontext中。

 這裡的Globals.ACTION_SERVLET_KEY在ActionServlet已經給了一個宣告:


public static final String ACTION_SERVLET_KEY= "org.apache.struts.action.ACTION_SERVLET";

接下来initModuleConfigFactory()方法,这个方法主要的作用是解析在web.xml中configFactory的text值。如果configFactory有配置,则将设置ModuleConfigFactory中得factoryClass值,否则默认得为efaultModuleConfigFactory。该方法其实宗旨是让开发人员自己开发出ModuleConfigFactory,从而得到自己所需要的ModuleConfig类。因为我们的实例中没有配置这个参数信息,所以我们这里的实例是要defalutModelConfigFactory了。

代码段一:


protected voidinitModuleConfigFactory(){ 
    String configFactory =getServletConfig().getInitParameter("configFactory"); 
    if (configFactory != null) { 
      ModuleConfigFactory.setFactoryClass(configFactory); 
    } 
}

代码段二:


public static void setFactoryClass(String factoryClass) { 
    ModuleConfigFactory.factoryClass = factoryClass; 
    ModuleConfigFactory.clazz = null; 
  }

代码段三:


protected static String factoryClass = 
    "org.apache.struts.config.impl.DefaultModuleConfigFactory"; 
}

ModuleConfig moduleConfig =initModuleConfig("", config)方法是非常重要的,initModuleConfig方法给strits-config里面的属性初始化后放入moduleConfig对象里面去,放到moduleConfig对象里面去便于以后操作更快,因为它是文件流。

具体实现代码:


protected ModuleConfig initModuleConfig(Stringprefix, String paths) 
    throws ServletException { 
  
    // :FIXME: Document UnavailableException? (Doesn&#39;t actually throw anything) 
  
    if (log.isDebugEnabled()) { 
      log.debug( 
        "Initializing module path &#39;" 
          + prefix 
          + "&#39; configuration from &#39;" 
          + paths 
          + "&#39;"); 
    } 
  
    // Parse the configuration for this module 
    ModuleConfigFactory factoryObject= ModuleConfigFactory.createFactory(); 
    ModuleConfig config =factoryObject.createModuleConfig(prefix); 
  
    // Configure the Digester instance we will use 
    Digester digester =initConfigDigester(); 
  
    // Process each specified resource path 
    while (paths.length() > 0) { 
      digester.push(config); 
      String path = null; 
      int comma = paths.indexOf(&#39;,&#39;); 
      if (comma >= 0) { 
        path =paths.substring(0, comma).trim(); 
        paths =paths.substring(comma + 1); 
      } else { 
        path = pathstrim(); 
        paths = ""; 
      } 
  
      if (pathlength() < 1){ 
        break; 
      } 
  
      this.parseModuleConfigFile(digester,path); 
    } 
  
    getServletContext().setAttribute( 
      Globals.MODULE_KEY +config.getPrefix(), 
      config); 
  
  
    // Force creation and registration of DynaActionFormClass instances 
    // for all dynamic form beans we wil be using 
    FormBeanConfig fbs[] =config.findFormBeanConfigs(); 
    for (int i = 0; i < fbs.length; i++) { 
      if (fbs[i].getDynamic()) { 
        fbs[i].getDynaActionFormClass(); 
      } 
    } 
  
    return config; 
}

这里有必要解析一下这段代码。首先得到继承ModuleConfigFactory的实现类,如果在initModuleConfigFactory()中能设置factoryClass属性,则能生成客户化得factory,否则得到得是默认得DefaultModuleConfigFactory类,该工厂得到ModuleConfigImpl类。然后调用initConfigDigester()该方法为解析配置文件做准备,初始化Digest类(具体digest的初始化实现就不讲解)。最后返回ModuleConfig,而这时的ModuleConfig里面封装了所有的struts-config.xml中的信息。

最后的几个方法就简单说一下就行,不是非常难理解:

initModuleMessageResources(moduleConfig)方法是通过moduleConfig中的配置文件信息,创建MessageResource对象.

initModuleDataSources(moduleConfig)方法是通过moduleConfig中的配置文件信息,创建DataSource对象.   initModulePlugIns(moduleConfig)加载并初始化默认应用模块的所有插件的。

moduleConfig.freeze()是将配置文件中的各个对象,设置成已配置状态.

最后我们看到了,下面还有一段同上面代码的循环代码,这段代码的主要意思就是当默认子应用模块被成功初始化后,如果应用还包括其他子应用模块,将重复流程,分别对其他子应用模块进行初始化。这个也是很好理解的。

到此为止ActionServlet就init完成。

以上是struts1之ActionServlet的實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。