欧美色欧美亚洲高清在线观看,国产特黄特色a级在线视频,国产一区视频一区欧美,亚洲成a 人在线观看中文

  1. <ul id="fwlom"></ul>

    <object id="fwlom"></object>

    <span id="fwlom"></span><dfn id="fwlom"></dfn>

      <object id="fwlom"></object>

      Struts 2框架分析

      時間:2019-05-13 15:49:52下載本文作者:會員上傳
      簡介:寫寫幫文庫小編為你整理了多篇相關(guān)的《Struts 2框架分析》,但愿對你工作學(xué)習(xí)有幫助,當然你在寫寫幫文庫還可以找到更多《Struts 2框架分析》。

      第一篇:Struts 2框架分析

      寧波工程學(xué)院學(xué)年論文

      Struts2框架分析

      湯禹鑫

      寧波工程學(xué)院,(315016)

      E-mail 372854786@qq.com

      摘 要: 本文對基于MVC模式,延續(xù)了Struts1和WebWork優(yōu)勢的WEB框架——Struts2框架的各個層次的組成、功能進行了詳細的介紹。關(guān)鍵詞:Struts2;框架;J2EE;

      1.引言

      Apache Struts2是一個為企業(yè)級應(yīng)用打造的優(yōu)秀的、可擴展的Web框架。該框架旨在充分精簡應(yīng)用程序的開發(fā)周期,從而減少創(chuàng)建、發(fā)布、應(yīng)用所花費的時間。而且對于Struts1有很多革命性的改進,但它并不是全新的框架,而是在WebWork框架的基礎(chǔ)上發(fā)展起來的。所以也可以說Struts2是WebWork的升級,吸收了Struts1和WebWork的優(yōu)勢,穩(wěn)定性、性能都有了很好的保證。

      2.Struts2的起源和背景

      2.1 Struts1

      在過去,Struts1是所有MVC框架中不容辯駁的勝利者。其程序運行流程如圖2-1所示。

      圖2-1 Struts 1的程序運行流程

      但是對于Struts 1框架而言,因為它與JSP/Servlet耦合非常緊密,因而導(dǎo)致了許多不可避免的缺陷,還有支持的表現(xiàn)層技術(shù)單

      一、代碼嚴重依賴于Struts 1 API。隨著Web應(yīng)用的拙見擴大,這些缺陷逐漸變成制約Struts 1發(fā)展的的重要因素——這也是Struts 2出現(xiàn)的原因。

      寧波工程學(xué)院學(xué)年論文

      (1)客戶端初始化一個指向Servlet容器(例如Tomcat)的請求;

      (2)這個請求經(jīng)過一系列的過濾器(Filter)(這些過濾器中有一個叫做ActionContextCleanUp的可選過濾器,這個過濾器對于Struts2和其它框架的集成很有幫助,例如:SiteMesh Plugin);

      (3)接著FilterDispatcher被調(diào)用,F(xiàn)ilterDispatcher詢問ActionMapper來決定這個請求是否需要調(diào)用某個Action;

      (4)如果ActionMapper決定需要調(diào)用某個Action,F(xiàn)ilterDispatcher把請求的處理交給ActionProxy;

      (5)ActionProxy通過Configuration Manager詢問框架的配置文件,找到需要調(diào)用的Action類;

      (6)ActionProxy創(chuàng)建一個ActionInvocation的實例;

      (7)ActionInvocation實例使用命名模式來調(diào)用,在調(diào)用Action的過程前后,涉及到相關(guān)攔截器(Intercepter)的調(diào)用;

      (8)一旦Action執(zhí)行完畢,ActionInvocation負責(zé)根據(jù)struts.xml中的配置找到對應(yīng)的返回結(jié)果。返回結(jié)果通常是(但不總是,也可能是另外的一個Action鏈)一個需要被表示的JSP或者FreeMarker的模版。在表示的過程中可以使用Struts 2 框架中繼承的標簽,在這個過程中需要涉及到ActionMapper。

      3.2 Struts 2配置文件

      Struts2 配置文件是用戶請求(View)和業(yè)務(wù)邏輯模塊(Model)Action 之間聯(lián)系的橋梁。開發(fā)者可以通過修改Struts2的配置文件來快速適應(yīng)業(yè)務(wù)需求,它是整個Struts2的精髓之一。當然,熟悉Struts1和WebWork的框架的人對配置文件一定不會陌生,同Struts1和WebWork框架一樣,Struts2框架配置文件也分為XML文件和屬性資源文件兩種。struts.xml 文件中包含了Action 的定義以及Action 的返回值對應(yīng)的視圖資源、命名空間等信息。此外,用戶也可以定義自己的XML文件,然后通過include指令將其包含到struts.xml文件中。另一類配置文件是屬性資源文件。資源文件中一般采用固定的Key-Value形式,用于定義Struts2 全局或者局部的資源數(shù)據(jù),例如定義國際化、開發(fā)模式等信息。

      3.3 Struts 2控制器

      Struts 2的控制器組建是Struts 2框架的核心,事實上所有MVC框架都是以控制器組件為核心的。正如前面提到的,Struts 2的控制器由兩個部分組成:FilterDispatcher和業(yè)務(wù)控制器Action。前者由框架提供,負責(zé)攔截所有的用戶請求,其過程如圖3-3所示

      寧波工程學(xué)院學(xué)年論文

      圖3-1 過濾器處理請求過程

      對于業(yè)務(wù)控制器Action,Struts 2框架為用戶提供了一個名為Action的接口,在接口中定義了SUCCESS、ERROR、INPUT、LOGIN、NONE五個靜態(tài)的字符串和一個execute方法,用戶在編寫自己的Action時只要實現(xiàn)該接口并重寫其中的execute方法,將所要實現(xiàn)的業(yè)務(wù)邏輯在該方法中處理就行了,當調(diào)用此Action時,Struts 2框架會自調(diào)用execute方法來完成所需的業(yè)務(wù)邏輯處理。實際上,在Struts2中起作用的業(yè)務(wù)邏輯并不是用戶自定義的Action ,而是系統(tǒng)生成的Action代理,只不過Action代理以用戶定義的Action為目標。

      3.4 Struts 2標簽庫

      于業(yè)Struts 2的標簽庫也是Struts 2的重要組成部分,Struts 2的標簽庫提供了非常豐富的功能,這些標簽不僅提供了表現(xiàn)層數(shù)據(jù)處理,而且還提供了基本的流程控制功能,還提供了國際化、Ajax支持等功能。使用標簽,開發(fā)者可以最大限度地減少頁面代碼的書寫。

      4.Struts 2框架應(yīng)用舉例

      例如課本上的Struts2用作登陸的例子,添加Struts 2功能框架核心需要如下三個步驟:(1)修改web.xml文件,在web.xml中配置Struts 2的核心Filter。

      struts2

      org.apache.struts2.dispatcher.FilterDispatcher

      (2)將Struts 2框架的類庫復(fù)制到Web應(yīng)用的WEB-INF/lib路徑下(也可以自己手動進行添加)。

      寧波工程學(xué)院學(xué)年論文

      5.結(jié)論

      Struts 2結(jié)合了Struts 1框架和WebWork框架的優(yōu)點,其框架的各個組件都是可靠的松散耦合。Struts 2最大的特點就是簡單性,引入了OGNL表達式和值棧的概念,可以用最單間的代碼實現(xiàn)復(fù)雜的數(shù)據(jù)訪問??偠灾?,Struts 2是一個當今Web開發(fā)中一個很重要而且功能足夠強大的框架,能讓我們更好地設(shè)計和完成Web應(yīng)用。

      參考文獻

      [1]鄭阿奇.J2EE應(yīng)用實踐教程.電子工業(yè)出版社,2011年7月.[2]李剛.Strut s2權(quán)威指南.電子工業(yè)出版社,2007年9月.[3]閆術(shù)卓.楊強.Strut s2技術(shù)詳解.電子工業(yè)出版社,2008年6月.

      第二篇:struts2代碼分析

      1.Struts2架構(gòu)圖和請求處理流程

      請求首先通過Filter chain,F(xiàn)ilter主要包括ActionContextCleanUp,它主要清理當前線程的ActionContext和Dispatcher;FilterDispatcher主要通過AcionMapper來決定需要調(diào)用哪個Action。

      ActionMapper取得了ActionMapping后,在Dispatcher的serviceAction方法里創(chuàng)建ActionProxy,ActionProxy創(chuàng)建ActionInvocation,然后ActionInvocation調(diào)用Interceptors,執(zhí)行Action本身,創(chuàng)建Result并返回,當然,如果要在返回之前做些什么,可以實現(xiàn)PreResultListener。

      2.Struts2部分類介紹

      這部分從Struts2參考文檔中翻譯就可以了。

      ActionMapper

      ActionMapper其實是HttpServletRequest和Action調(diào)用請求的一個映射,它屏蔽了Action對于Request等java Servlet類的依賴。Struts2中它的默認實現(xiàn)類是DefaultActionMapper,ActionMapper很大的用處可以根據(jù)自己的需要來設(shè)計url格式,它自己也有Restful的實現(xiàn),具體可以參考文檔的docs¥actionmapper.html。

      ActionProxy&ActionInvocation

      Action的一個代理,由ActionProxyFactory創(chuàng)建,它本身不包括Action實例,默認實現(xiàn)DefaultActionProxy是由ActionInvocation持有Action實例。ActionProxy作用是如何取得Action,無論是本地還是遠程。而ActionInvocation的作用是如何執(zhí)行Action,攔截器的功能就是在ActionInvocation中實現(xiàn)的。

      ConfigurationProvider&Configuration

      ConfigurationProvider就是Struts2中配置文件的解析器,Struts2中的配置文件主要是尤其實現(xiàn)類XmlConfigurationProvider及其子類StrutsXmlConfigurationProvider來解析。

      3.Struts2請求流程

      1、客戶端發(fā)送請求

      2、請求先通過ActionContextCleanUp-->FilterDispatcher

      3、FilterDispatcher通過ActionMapper來決定這個Request需要調(diào)用哪個Action

      4、如果ActionMapper決定調(diào)用某個Action,F(xiàn)ilterDispatcher把請求的處理交給ActionProxy,這兒已經(jīng)轉(zhuǎn)到它的Delegate--Dispatcher來執(zhí)行

      5、ActionProxy根據(jù)ActionMapping和ConfigurationManager找到需要調(diào)用的Action類

      6、ActionProxy創(chuàng)建一個ActionInvocation的實例

      7、ActionInvocation調(diào)用真正的Action,當然這涉及到相關(guān)攔截器的調(diào)用

      8、Action執(zhí)行完畢,ActionInvocation創(chuàng)建Result并返回,當然,如果要在返回之前做些什么,可以實現(xiàn)PreResultListener。添加PreResultListener可以在Interceptor中實現(xiàn)。

      首先強調(diào)一下struts2的線程程安全,在Struts2中大量采用ThreadLocal線程局部變量的方法來保證線程的安全,像Dispatcher等都是通過ThreadLocal來保存變量值,使得每個線程都有自己獨立的實例變量,互不相干.接下來就從Dispatcher開始看起,先看其構(gòu)造函數(shù):

      //創(chuàng)建Dispatcher,此類是一個Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對應(yīng)Action的地方

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

      //配置在web.xml中的param參數(shù)

      this.initParams = initParams;

      }

      //創(chuàng)建Dispatcher,此類是一個Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對應(yīng)Action的地方

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

      //配置在web.xml中的param參數(shù)

      this.initParams = initParams;

      }

      我們再看在FilterDispatcher創(chuàng)建Dispatcher的:

      protected Dispatcher createDispatcher(FilterConfig filterConfig){

      Map params = new HashMap();

      for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

      String name =(String)e.nextElement();

      String value = filterConfig.getInitParameter(name);

      params.put(name, value);

      }

      都可以從FilterConfig中得到

      return new Dispatcher(filterConfig.getServletContext(), params);

      }

      protected Dispatcher createDispatcher(FilterConfig filterConfig){

      Map params = new HashMap();

      for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

      String name =(String)e.nextElement();

      String value = filterConfig.getInitParameter(name);

      params.put(name, value);

      }

      都可以從FilterConfig中得到

      return new Dispatcher(filterConfig.getServletContext(), params);

      }

      分七步載入各種配置屬性,都是通過ConfigurationProvider接口進行的,這個接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實現(xiàn)對配置文件的屬性進行注冊和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

      創(chuàng)建Dispatcher之后,來看init()方法

      init()方法是用來Load用戶配置文件,資源文件以及默認的配置文件.主要分七步走,看下面注釋

      public void init(){

      if(configurationManager == null){

      //設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

      configurationManager

      =

      new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

      }

      //讀取properties信息,默認的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

      //讀取用戶自定義的struts.properties

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進來的initParams

      init_FilterInitParameters();// [6]

      //將配置文件中的bean與具體的類映射

      init_AliasStandardObjects();// [7]

      //構(gòu)建一個用于依賴注射的Container對象

      //在這里面會循環(huán)調(diào)用上面七個ConfigurationProvider的register方法

      //其中的重點就是DefaultConfiguration的#reload()方法

      Container container = init_PreloadConfiguration();

      container.inject(this);

      init_CheckConfigurationReloading(container);

      init_CheckWebLogicWorkaround(container);

      if(!dispatcherListeners.isEmpty()){

      for(DispatcherListener l : dispatcherListeners){

      l.dispatcherInitialized(this);

      }

      }

      }

      public void init(){

      if(configurationManager == null){

      //設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

      configurationManager

      =

      new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

      }

      //讀取properties信息,默認的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

      //讀取用戶自定義的struts.properties

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進來的initParams

      init_FilterInitParameters();// [6]

      //將配置文件中的bean與具體的類映射

      init_AliasStandardObjects();// [7]

      //構(gòu)建一個用于依賴注射的Container對象

      //在這里面會循環(huán)調(diào)用上面七個ConfigurationProvider的register方法

      //其中的重點就是DefaultConfiguration的#reload()方法

      Container container = init_PreloadConfiguration();

      container.inject(this);

      init_CheckConfigurationReloading(container);

      init_CheckWebLogicWorkaround(container);

      if(!dispatcherListeners.isEmpty()){

      for(DispatcherListener l : dispatcherListeners){

      l.dispatcherInitialized(this);

      }

      }

      }

      分七步載入各種配置屬性,都是通過ConfigurationProvider接口進行的,這個接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實現(xiàn)對配置文件的屬性進行注冊和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

      private void init_DefaultProperties(){

      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

      }

      接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實際上只是實現(xiàn)了register()方法

      public void register(ContainerBuilder builder, LocatableProperties props)

      throws ConfigurationException {

      Settings defaultSettings = null;

      try {

      defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

      } catch(Exception e){

      throw

      }

      loadSettings(props, defaultSettings);

      }

      private void init_DefaultProperties(){

      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

      }

      接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實際上只是實現(xiàn)了register()方法

      public void register(ContainerBuilder builder, LocatableProperties props)

      throws ConfigurationException {

      Settings defaultSettings = null;

      try {

      defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

      } catch(Exception e){

      new

      ConfigurationException(“Could

      not

      find

      or

      error

      in org/apache/struts2/default.properties”, e);

      throw

      }

      new ConfigurationException(“Could not find or error in org/apache/struts2/default.properties”, e);

      loadSettings(props, defaultSettings);

      }

      //PropertiesSettings構(gòu)造方法

      //讀取org/apache/struts2/default.properties的配置信息,如果項目中需要覆蓋,可以在classpath里的struts.properties里覆寫

      public PropertiesSettings(String name){

      URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

      if(settingsUrl == null){

      LOG.debug(name + “.properties missing”);

      settings = new LocatableProperties();

      return;

      }

      settings

      // Load settings

      InputStream in = null;

      try {

      in = settingsUrl.openStream();

      settings.load(in);

      } catch(IOException e){

      throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

      } finally {

      if(in!= null){

      try {

      =

      new

      LocatableProperties(new

      LocationImpl(null, settingsUrl.toString()));

      in.close();

      } catch(IOException io){

      LOG.warn(“Unable to close input stream”, io);

      }

      }

      }

      }

      //loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

      //這個props是register的一個入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

      // We are calling the impl methods to get around the single instance of Settings that is expected

      for(Iterator i = settings.listImpl();i.hasNext();){

      String name =(String)i.next();

      props.setProperty(name, settings.getLocationImpl(name));

      }

      }

      //PropertiesSettings構(gòu)造方法

      //讀取org/apache/struts2/default.properties的配置信息,如果項目中需要覆蓋,可以在classpath里的struts.properties里覆寫

      public PropertiesSettings(String name){

      URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

      if(settingsUrl == null){

      LOG.debug(name + “.properties missing”);

      settings = new LocatableProperties();

      return;

      }

      settings =

      new

      LocatableProperties(new

      LocationImpl(null, settingsUrl.toString()));

      settings.getImpl(name),// Load settings

      InputStream in = null;

      try {

      in = settingsUrl.openStream();

      settings.load(in);

      } catch(IOException e){

      throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

      } finally {

      if(in!= null){

      try {

      in.close();

      } catch(IOException io){

      LOG.warn(“Unable to close input stream”, io);

      }

      }

      }

      }

      //loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

      //這個props是register的一個入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

      // We are calling the impl methods to get around the single instance of Settings that is expected

      for(Iterator i = settings.listImpl();i.hasNext();){

      String name =(String)i.next();

      props.setProperty(name, settings.getLocationImpl(name));

      }

      }

      再來看第二步:init_TraditionalXmlConfigurations()

      private void init_TraditionalXmlConfigurations(){

      settings.getImpl(name), //首先讀取web.xml中的config初始參數(shù)值

      //如果

      使

      認的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認的配置文件必須取名為這三個名稱了

      //如果不想使用默認的名稱,直接在web.xml中配置config初始參數(shù)即可

      String configPaths = initParams.get(“config”);

      if(configPaths == null){

      configPaths = DEFAULT_CONFIGURATION_PATHS;

      }

      String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

      for(String file : files){

      if(file.endsWith(“.xml”)){

      if(“xwork.xml”.equals(file)){

      //XmlConfigurationProvider負責(zé)解析xwork.xml

      configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

      } else {

      //其它xml都是由StrutsXmlConfigurationProvider來解析

      configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

      }

      } else {

      throw new IllegalArgumentException(“Invalid configuration file name”);

      }

      }

      }

      private void init_TraditionalXmlConfigurations(){

      //首先讀取web.xml中的config初始參數(shù)值

      //如果

      使

      認的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認的配置文件必須取名為這三個名稱了

      //如果不想使用默認的名稱,直接在web.xml中配置config初始參數(shù)即可

      String configPaths = initParams.get(“config”);

      if(configPaths == null){

      configPaths = DEFAULT_CONFIGURATION_PATHS;

      }

      String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

      for(String file : files){

      if(file.endsWith(“.xml”)){

      if(“xwork.xml”.equals(file)){

      //XmlConfigurationProvider負責(zé)解析xwork.xml

      configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

      } else {

      //其它xml都是由StrutsXmlConfigurationProvider來解析

      configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

      }

      } else {

      throw new IllegalArgumentException(“Invalid configuration file name”);

      }

      }

      }

      對于其它配置文件只用接口。

      類XmlConfigurationProvider負責(zé)配置文件的讀取和解析,首先通過init()中的loadDocuments(configFileName);利用DomHelper中的

      public static Document parse(InputSource inputSource, Map dtdMappings)將configFileName配置文件通過SAX解析方式按照DtdMappings解析成Document對象.然后通過Provider的register()方法加載“bean”和“constant”屬性,再通過loadPackages()加載package及package中的屬性

      addAction()方法負責(zé)讀取標簽,并將數(shù)據(jù)保存在ActionConfig中; addResultTypes()方法負責(zé)將標簽轉(zhuǎn)化為ResultTypeConfig對象; loadInterceptors()方法負責(zé)將標簽轉(zhuǎn)化為InterceptorConfi對象;

      loadInterceptorStack()方法負責(zé)將標簽轉(zhuǎn)化為InterceptorStackConfig對象;

      StrutsXmlConfigurationProvider,此類繼承XmlConfigurationProvider,而XmlConfigurationProvider又實現(xiàn)ConfigurationProviderloadInterceptorStacks()方法負責(zé)將標簽轉(zhuǎn)化成InterceptorStackConfig對象。

      而上面的方法最終會被addPackage()方法調(diào)用,addPackage又會被Provider的loadPackages()調(diào)用,將所讀取到的數(shù)據(jù)匯集到PackageConfig對象中。

      protected PackageConfig

      addPackage(Element

      packageElement)

      throws ConfigurationException {

      PackageConfig.Builder newPackage = buildPackageContext(packageElement);

      if(newPackage.isNeedsRefresh()){

      return newPackage.build();

      }

      // add result types(and default result)to this package

      addResultTypes(newPackage, packageElement);

      // load the interceptors and interceptor stacks for this package

      loadInterceptors(newPackage, packageElement);

      // load the default interceptor reference for this package

      loadDefaultInterceptorRef(newPackage, packageElement);

      // load the default class ref for this package

      loadDefaultClassRef(newPackage, packageElement);

      // load the global result list for this package

      loadGlobalResults(newPackage, packageElement);

      // load the global exception handler list for this package

      loadGobalExceptionMappings(newPackage, packageElement);

      // get actions

      NodeList actionList = packageElement.getElementsByTagName(“action”);

      for(int i = 0;i < actionList.getLength();i++){

      Element actionElement =(Element)actionList.item(i);

      addAction(actionElement, newPackage);

      }

      // load the default action reference for this package

      loadDefaultActionRef(newPackage, packageElement);

      PackageConfig cfg = newPackage.build();

      configuration.addPackageConfig(cfg.getName(), cfg);

      return cfg;

      }

      loadConfigurationFiles解析讀取xml中的內(nèi)容

      private List

      loadConfigurationFiles(String

      fileName,Element includeElement){

      ...//通過DomHelper調(diào)用SAX進行解析xml

      doc = DomHelper.parse(in, dtdMappings);

      ...Element rootElement = doc.getDocumentElement();

      NodeList children = rootElement.getChildNodes();

      int childSize = children.getLength();

      for(int i = 0;i < childSize;i++){

      Node childNode = children.item(i);

      if(childNode instanceof Element){

      Element child =(Element)childNode;

      final String nodeName = child.getNodeName();

      if(“include”.equals(nodeName)){

      String includeFileName = child.getAttribute(“file”);

      //解析每個action配置是,對于include文件可以使用通配符*來進行配置

      //如Struts.xml中可配置成

      if(includeFileName.indexOf('*')!=-1){

      ClassPathFinder wildcardFinder = new ClassPathFinder();

      wildcardFinder.setPattern(includeFileName);

      Vector wildcardMatches = wildcardFinder.findMatches();

      for(String match : wildcardMatches){

      //遞歸Load子file中的

      docs.addAll(loadConfigurationFiles(match, child));

      }

      } else {

      docs.addAll(loadConfigurationFiles(includeFileName, child));

      }

      }

      }

      }

      docs.add(doc);

      loadedFileUrls.add(url.toString());

      ...return docs;

      }

      首先強調(diào)一下struts2的線程程安全,在Struts2中大量采用ThreadLocal線程局部變量的方法來保證線程的安全,像Dispatcher等都是通過ThreadLocal來保存變量值,使得每個線程都有自己獨立的實例變量,互不相干.接下來就從Dispatcher開始看起,先看其構(gòu)造函數(shù):

      //創(chuàng)建Dispatcher,此類是一個Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對應(yīng)Action的地方

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

      //配置在web.xml中的param參數(shù)

      this.initParams = initParams;

      }

      //創(chuàng)建Dispatcher,此類是一個Delegate,它是真正完成根據(jù)url解析轉(zhuǎn)向,讀取對應(yīng)Action的地方

      public Dispatcher(ServletContext servletContext, Map initParams){

      this.servletContext = servletContext;

      //配置在web.xml中的param參數(shù)

      this.initParams = initParams;

      }

      我們再看在FilterDispatcher創(chuàng)建Dispatcher的:

      protected Dispatcher createDispatcher(FilterConfig filterConfig){

      Map params = new HashMap();

      for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

      String name =(String)e.nextElement();

      String value = filterConfig.getInitParameter(name);

      params.put(name, value);

      }

      都可以從FilterConfig中得到

      return new Dispatcher(filterConfig.getServletContext(), params);

      }

      protected Dispatcher createDispatcher(FilterConfig filterConfig){

      Map params = new HashMap();

      for(Enumeration e = filterConfig.getInitParameterNames();e.hasMoreElements();){

      String name =(String)e.nextElement();

      String value = filterConfig.getInitParameter(name);

      params.put(name, value);

      }

      都可以從FilterConfig中得到

      return new Dispatcher(filterConfig.getServletContext(), params);

      }

      分七步載入各種配置屬性,都是通過ConfigurationProvider接口進行的,這個接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實現(xiàn)對配置文件的屬性進行注冊和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

      創(chuàng)建Dispatcher之后,來看init()方法

      init()方法是用來Load用戶配置文件,資源文件以及默認的配置文件.主要分七步走,看下面注釋

      public void init(){

      if(configurationManager == null){

      //設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

      configurationManager = ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

      }

      //讀取properties信息,默認的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

      //讀取用戶自定義的struts.properties

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進來的initParams

      init_FilterInitParameters();// [6]

      //將配置文件中的bean與具體的類映射

      init_AliasStandardObjects();// [7]

      //構(gòu)建一個用于依賴注射的Container對象

      //在這里面會循環(huán)調(diào)用上面七個ConfigurationProvider的register方法

      //其中的重點就是DefaultConfiguration的#reload()方法

      Container container = init_PreloadConfiguration();

      container.inject(this);

      init_CheckConfigurationReloading(container);

      init_CheckWebLogicWorkaround(container);

      if(!dispatcherListeners.isEmpty()){

      for(DispatcherListener l : dispatcherListeners){

      l.dispatcherInitialized(this);

      }

      }

      new

      }

      public void init(){

      if(configurationManager == null){

      //設(shè)置ConfigurationManager的defaultFrameworkBeanName.//這里DEFAULT_BEAN_NAME為struts,這是xwork框架的內(nèi)容,Framework可以是xwork,struts,webwork等

      configurationManager = ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);

      }

      //讀取properties信息,默認的default.properties,init_DefaultProperties();// [1]

      //讀取xml配置文件

      init_TraditionalXmlConfigurations();// [2]

      //讀取用戶自定義的struts.properties

      init_LegacyStrutsProperties();// [3]

      //自定義的configProviders

      init_CustomConfigurationProviders();// [5]

      //載入FilterDispatcher傳進來的initParams

      init_FilterInitParameters();// [6]

      //將配置文件中的bean與具體的類映射

      init_AliasStandardObjects();// [7]

      //構(gòu)建一個用于依賴注射的Container對象

      //在這里面會循環(huán)調(diào)用上面七個ConfigurationProvider的register方法

      //其中的重點就是DefaultConfiguration的#reload()方法

      Container container = init_PreloadConfiguration();

      container.inject(this);

      init_CheckConfigurationReloading(container);

      init_CheckWebLogicWorkaround(container);

      if(!dispatcherListeners.isEmpty()){

      for(DispatcherListener l : dispatcherListeners){

      l.dispatcherInitialized(this);

      }

      }

      new

      }

      分七步載入各種配置屬性,都是通過ConfigurationProvider接口進行的,這個接口提供init(),destroy(),register()等方法.將各種ConfigurationProvider初始化之后將實例添加到ConfigurationManager的List里面.最后通過循環(huán)調(diào)用List里的這些destroy(),register()等方法實現(xiàn)對配置文件的屬性進行注冊和銷毀等功能.下面將分析這七層功夫是怎樣一步步練成的.首先是init_DefaultProperties()

      private void init_DefaultProperties(){

      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

      }

      接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實際上只是實現(xiàn)了register()方法

      public void register(ContainerBuilder builder, LocatableProperties props)

      throws ConfigurationException {

      Settings defaultSettings = null;

      try {

      defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

      } catch(Exception e){

      throw

      }

      loadSettings(props, defaultSettings);

      }

      private void init_DefaultProperties(){

      configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

      }

      接來看DefaultPropertiesProvider好了,DefaultPropertiesProvider實際上只是實現(xiàn)了new

      ConfigurationException(“Could

      not

      find

      or

      error

      in org/apache/struts2/default.properties”, e);

      register()方法

      public void register(ContainerBuilder builder, LocatableProperties props)

      throws ConfigurationException {

      Settings defaultSettings = null;

      try {

      defaultSettings = new PropertiesSettings(“org/apache/struts2/default”);

      } catch(Exception e){

      throw

      }

      loadSettings(props, defaultSettings);

      }

      //PropertiesSettings構(gòu)造方法

      //讀取org/apache/struts2/default.properties的配置信息,如果項目中需要覆蓋,可以在classpath里的struts.properties里覆寫

      public PropertiesSettings(String name){

      URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

      if(settingsUrl == null){

      LOG.debug(name + “.properties missing”);

      settings = new LocatableProperties();

      return;

      }

      settings

      // Load settings

      InputStream in = null;

      try {

      =

      new

      LocatableProperties(new

      LocationImpl(null, settingsUrl.toString()));

      new

      ConfigurationException(“Could

      not

      find

      or

      error

      in org/apache/struts2/default.properties”, e);

      in = settingsUrl.openStream();

      settings.load(in);

      } catch(IOException e){

      throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

      } finally {

      if(in!= null){

      try {

      in.close();

      } catch(IOException io){

      LOG.warn(“Unable to close input stream”, io);

      }

      }

      }

      }

      //loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

      //這個props是register的一個入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

      // We are calling the impl methods to get around the single instance of Settings that is expected

      for(Iterator i = settings.listImpl();i.hasNext();){

      String name =(String)i.next();

      props.setProperty(name, settings.getLocationImpl(name));

      }

      }

      //PropertiesSettings構(gòu)造方法

      //讀取org/apache/struts2/default.properties的配置信息,如果項目中需要覆蓋,可以在classpath里的struts.properties里覆寫

      public PropertiesSettings(String name){

      URL settingsUrl = ClassLoaderUtils.getResource(name + “.properties”, getClass());

      settings.getImpl(name),if(settingsUrl == null){

      LOG.debug(name + “.properties missing”);

      settings = new LocatableProperties();

      return;

      }

      settings

      // Load settings

      InputStream in = null;

      try {

      in = settingsUrl.openStream();

      settings.load(in);

      } catch(IOException e){

      throw new StrutsException(“Could not load ” + name + “.properties:” + e, e);

      } finally {

      if(in!= null){

      try {

      in.close();

      } catch(IOException io){

      LOG.warn(“Unable to close input stream”, io);

      }

      }

      }

      }

      //loadSettings主要是將progerty的value和Locale從上面PropertiesSettings中取得并存放到LocatableProperties props

      //這個props是register的一個入?yún)?protected void loadSettings(LocatableProperties props, final Settings settings){

      // We are calling the impl methods to get around the single instance of Settings that is expected

      for(Iterator i = settings.listImpl();i.hasNext();){

      String name =(String)i.next();

      =

      new

      LocatableProperties(new

      LocationImpl(null, settingsUrl.toString()));

      props.setProperty(name, settings.getLocationImpl(name));

      }

      }

      再來看第二步:init_TraditionalXmlConfigurations()

      private void init_TraditionalXmlConfigurations(){

      //首先讀取web.xml中的config初始參數(shù)值

      //如果

      使

      settings.getImpl(name),用默認的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認的配置文件必須取名為這三個名稱了

      //如果不想使用默認的名稱,直接在web.xml中配置config初始參數(shù)即可

      String configPaths = initParams.get(“config”);

      if(configPaths == null){

      configPaths = DEFAULT_CONFIGURATION_PATHS;

      }

      String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

      for(String file : files){

      if(file.endsWith(“.xml”)){

      if(“xwork.xml”.equals(file)){

      //XmlConfigurationProvider負責(zé)解析xwork.xml

      configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

      } else {

      //其它xml都是由StrutsXmlConfigurationProvider來解析

      configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

      }

      } else {

      throw new IllegalArgumentException(“Invalid configuration file name”);

      }

      }

      }

      private void init_TraditionalXmlConfigurations(){

      //首先讀取web.xml中的config初始參數(shù)值

      //如果

      使

      認的DEFAULT_CONFIGURATION_PATHS:“struts-default.xml,struts-plugin.xml,struts.xml”,//這兒就可以看出為什么默認的配置文件必須取名為這三個名稱了

      //如果不想使用默認的名稱,直接在web.xml中配置config初始參數(shù)即可

      String configPaths = initParams.get(“config”);

      if(configPaths == null){

      configPaths = DEFAULT_CONFIGURATION_PATHS;

      }

      String[] files = configPaths.split(“¥¥s*[,]¥¥s*”);

      for(String file : files){

      if(file.endsWith(“.xml”)){

      if(“xwork.xml”.equals(file)){

      //XmlConfigurationProvider負責(zé)解析xwork.xml

      configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));

      } else {

      //其它xml都是由StrutsXmlConfigurationProvider來解析

      configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));

      }

      } else {

      throw new IllegalArgumentException(“Invalid configuration file name”);

      }

      }

      }

      對于其它配置文件只用接口。

      類XmlConfigurationProvider負責(zé)配置文件的讀取和解析,首先通過init()中的loadDocuments(configFileName);利用DomHelper中的

      public static Document parse(InputSource inputSource, Map dtdMappings)將configFileName配置文件通過SAX解析方式按照DtdMappings解析成StrutsXmlConfigurationProvider,此類繼承XmlConfigurationProvider,而XmlConfigurationProvider又實現(xiàn)ConfigurationProviderDocument對象.然后通過Provider的register()方法加載“bean”和“constant”屬性,再通過loadPackages()加載package及package中的屬性

      addAction()方法負責(zé)讀取標簽,并將數(shù)據(jù)保存在ActionConfig中; addResultTypes()方法負責(zé)將標簽轉(zhuǎn)化為ResultTypeConfig對象; loadInterceptors()方法負責(zé)將標簽轉(zhuǎn)化為InterceptorConfi對象;

      loadInterceptorStack()方法負責(zé)將標簽轉(zhuǎn)化為InterceptorStackConfig對象;

      loadInterceptorStacks()方法負責(zé)將標簽轉(zhuǎn)化成InterceptorStackConfig對象。

      而上面的方法最終會被addPackage()方法調(diào)用,addPackage又會被Provider的loadPackages()調(diào)用,將所讀取到的數(shù)據(jù)匯集到PackageConfig對象中。

      protected PackageConfig

      addPackage(Element

      packageElement)

      throws ConfigurationException {

      PackageConfig.Builder newPackage = buildPackageContext(packageElement);

      if(newPackage.isNeedsRefresh()){

      return newPackage.build();

      }

      // add result types(and default result)to this package

      addResultTypes(newPackage, packageElement);

      // load the interceptors and interceptor stacks for this package

      loadInterceptors(newPackage, packageElement);

      // load the default interceptor reference for this package

      loadDefaultInterceptorRef(newPackage, packageElement);

      // load the default class ref for this package

      loadDefaultClassRef(newPackage, packageElement);

      // load the global result list for this package

      loadGlobalResults(newPackage, packageElement);

      // load the global exception handler list for this package

      loadGobalExceptionMappings(newPackage, packageElement);

      // get actions

      NodeList actionList = packageElement.getElementsByTagName(“action”);

      for(int i = 0;i < actionList.getLength();i++){

      Element actionElement =(Element)actionList.item(i);

      addAction(actionElement, newPackage);

      }

      // load the default action reference for this package

      loadDefaultActionRef(newPackage, packageElement);

      PackageConfig cfg = newPackage.build();

      configuration.addPackageConfig(cfg.getName(), cfg);

      return cfg;

      }

      loadConfigurationFiles解析讀取xml中的內(nèi)容

      private List

      loadConfigurationFiles(String

      fileName, includeElement){

      ...//通過DomHelper調(diào)用SAX進行解析xml

      doc = DomHelper.parse(in, dtdMappings);

      ...Element rootElement = doc.getDocumentElement();

      NodeList children = rootElement.getChildNodes();

      int childSize = children.getLength();

      for(int i = 0;i < childSize;i++){

      Node childNode = children.item(i);

      if(childNode instanceof Element){

      Element child =(Element)childNode;

      final String nodeName = child.getNodeName();

      if(“include”.equals(nodeName)){

      String includeFileName = child.getAttribute(“file”);

      //解析每個action配置是,對于include文件可以使用通配符*來進行配置

      //如Struts.xml中可配置成

      if(includeFileName.indexOf('*')!=-1){

      ClassPathFinder wildcardFinder = new ClassPathFinder();

      wildcardFinder.setPattern(includeFileName);

      Element

      Vector wildcardMatches = wildcardFinder.findMatches();

      for(String match : wildcardMatches){

      //遞歸Load子file中的

      docs.addAll(loadConfigurationFiles(match, child));

      }

      } else {

      docs.addAll(loadConfigurationFiles(includeFileName, child));

      }

      }

      }

      }

      docs.add(doc);

      loadedFileUrls.add(url.toString());

      ...return docs;

      }

      接下來第三步:init_LegacyStrutsProperties()調(diào)用的是調(diào)用的是LegacyPropertiesConfigurationProvider 通過比較前

      DefaultPropertiesProvider

      調(diào)

      用的是LegacyPropertiesConfigurationProvider.發(fā)現(xiàn)DefaultPropertiesProvider繼承自后者,但重寫了register()方法,主要是生成PropertiesSetting的不同,前者是根據(jù)org/apache/struts2/default.properties 后者是根據(jù)struts.properties 我們展開register()中的Settings.getInstance(),最后是調(diào)用getDefaultInstance()

      private static Settings getDefaultInstance(){

      if(defaultImpl == null){

      // Create bootstrap implementation

      //不帶參數(shù)的DefaultSettings(),區(qū)別與DefaultPropertiesProvider中直接帶default.properties參數(shù)

      //不帶參數(shù)就是默認為struts.propertes,并且加載struts.custom.properties所定義的properties文件

      defaultImpl = new DefaultSettings();

      // Create default implementation

      try {

      //STRUTS_CONFIGURATION為:struts.configuration

      //在struts.proterties中查找struts.configuration的值,這個值必須是org.apache.struts2.config.Configuration接口的實現(xiàn)類

      //所以我有個困惑就是在下面的轉(zhuǎn)換當中怎么將Configuration轉(zhuǎn)換成Setting類型的...//這一點先放下了,有時間再研究

      String className = get(StrutsConstants.STRUTS_CONFIGURATION);

      if(!className.equals(defaultImpl.getClass().getName())){

      try {

      // singleton instances shouldn't be built accessing request or session-specific context data

      defaultImpl oader().loadClass(className), null);

      } catch(Exception e){

      LOG.error(“Settings:

      }

      }

      } catch(IllegalArgumentException ex){

      // ignore

      }

      private static Settings getDefaultInstance(){

      if(defaultImpl == null){

      // Create bootstrap implementation

      //不帶參數(shù)的DefaultSettings(),區(qū)別與DefaultPropertiesProvider中直接帶default.properties參數(shù)

      //不帶參數(shù)就是默認為struts.propertes,并且加載struts.custom.properties所定義的properties文件

      defaultImpl = new DefaultSettings();

      // Create default implementation

      try {

      //STRUTS_CONFIGURATION為:struts.configuration

      //在struts.proterties中查找struts.configuration的值,這個值必須是

      Could

      not

      instantiate

      the struts.configuration object, substituting the default implementation.”, e);

      =

      (Settings)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassLorg.apache.struts2.config.Configuration接口的實現(xiàn)類

      //所以我有個困惑就是在下面的轉(zhuǎn)換當中怎么將Configuration轉(zhuǎn)換成Setting類型的...//這一點先放下了,有時間再研究

      String className = get(StrutsConstants.STRUTS_CONFIGURATION);

      if(!className.equals(defaultImpl.getClass().getName())){

      try {

      // singleton instances shouldn't be built accessing request or session-specific context data

      defaultImpl oader().loadClass(className), null);

      } catch(Exception e){

      LOG.error(“Settings:

      }

      }

      } catch(IllegalArgumentException ex){

      // ignore

      }

      在2.1.6中去掉了第四步:init_ZeroConfiguration();第五步是自定義的configProviders

      private void init_CustomConfigurationProviders(){

      //從這里可以看到可以將自定義的Provider定義在web.xml中FilterDispatcher的param中:configProviders

      String configProvs = initParams.get(”configProviders“);

      if(configProvs!= null){

      String[] classes = configProvs.split(”¥¥s*[,]¥¥s*“);

      for(String cname : classes){

      try {

      Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());

      ConfigurationProvider(ConfigurationProvider)cls.newInstance();

      configurationManager.addConfigurationProvider(prov);

      prov

      =

      Could

      not

      instantiate

      the struts.configuration object, substituting the default implementation.”, e);

      =

      (Settings)ObjectFactory.getObjectFactory().buildBean(Thread.currentThread().getContextClassL

      }

      ...}

      }

      }

      private void init_CustomConfigurationProviders(){

      //從這里可以看到可以將自定義的Provider定義在web.xml中FilterDispatcher的param中:configProviders

      String configProvs = initParams.get(“configProviders”);

      if(configProvs!= null){

      String[] classes = configProvs.split(“¥¥s*[,]¥¥s*”);

      for(String cname : classes){

      try {

      Class cls = ClassLoaderUtils.loadClass(cname, this.getClass());

      ConfigurationProvider(ConfigurationProvider)cls.newInstance();

      configurationManager.addConfigurationProvider(prov);

      }

      ...}

      }

      }

      第六步:init_FilterInitParameters

      //從這里可以看出struts.properties中的屬性不僅可以在struts.xml中以constant形式定義,而且可以在FilterDispatcher的param中定義

      private void init_FilterInitParameters(){

      configurationManager.addConfigurationProvider(new ConfigurationProvider(){

      public void destroy(){}

      public

      void

      init(Configuration

      configuration)

      throws ConfigurationException {}

      public void loadPackages()throws ConfigurationException {}

      public boolean needsReload(){ return false;}

      prov

      =

      public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {

      props.putAll(initParams);//在這里實現(xiàn)滴~

      }

      });

      }

      //從這里可以看出struts.properties中的屬性不僅可以在struts.xml中以constant形式定義,而且可以在FilterDispatcher的param中定義

      private void init_FilterInitParameters(){

      configurationManager.addConfigurationProvider(new ConfigurationProvider(){

      public void destroy(){}

      public

      void

      init(Configuration

      configuration)

      throws ConfigurationException {}

      public void loadPackages()throws ConfigurationException {}

      public boolean needsReload(){ return false;}

      public void register(ContainerBuilder builder, LocatableProperties props)throws ConfigurationException {

      props.putAll(initParams);//在這里實現(xiàn)滴~

      }

      });

      }

      第七步:init_AliasStandardObjects,使用BeanSelectionProvider 這是將配置文件中定義的與實際的類相映射,就是注入bean的依賴關(guān)系,這部分以后有時候再研究Container

      接下來是看怎樣調(diào)用這些ConfigurationProviders 展開init_PreloadConfiguration()

      private Container init_PreloadConfiguration(){

      Configuration config = configurationManager.getConfiguration();

      Container container = config.getContainer();

      boolean reloadi18n = Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));

      LocalizedTextUtil.setReloadBundles(reloadi18n);

      return container;

      }

      //再看getConfiguration()

      public synchronized Configuration getConfiguration(){

      if(configuration == null){

      setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));

      try {

      //重點就是這個reloadContainer

      configuration.reloadContainer(getContainerProviders());

      } catch(ConfigurationException e){

      setConfiguration(null);

      throw new ConfigurationException(“Unable to load configuration.”, e);

      }

      } else {

      conditionalReload();

      }

      return configuration;

      }

      private Container init_PreloadConfiguration(){

      Configuration config = configurationManager.getConfiguration();

      Container container = config.getContainer();

      boolean reloadi18n

      =

      Boolean.valueOf(container.getInstance(String.class, StrutsConstants.STRUTS_I18N_RELOAD));

      LocalizedTextUtil.setReloadBundles(reloadi18n);

      return container;

      }

      //再看getConfiguration()

      public synchronized Configuration getConfiguration(){

      if(configuration == null){

      setConfiguration(new DefaultConfiguration(defaultFrameworkBeanName));

      try {

      //重點就是這個reloadContainer

      configuration.reloadContainer(getContainerProviders());

      } catch(ConfigurationException e){

      setConfiguration(null);

      throw new ConfigurationException(“Unable to load configuration.”, e);

      }

      } else {

      conditionalReload();

      }

      return configuration;

      }

      展開DefaultConfiguration中的reloadContainer

      public synchronized List

      reloadContainer(List providers)throws ConfigurationException {

      packageContexts.clear();

      loadedFileNames.clear();

      List

      packageProviders = new ArrayList

      ();

      //Struts2(xwork2)用Container來完成依賴注入的功能

      //首先初始化一個ContainerBuilder,再由builder來保存接口與實現(xiàn)類或工廠類的對應(yīng)關(guān)系

      //然后通過builder.create(boolean)方法產(chǎn)生container

      //由container.getInstance(Class);就可以得到接口的實現(xiàn)實例了

      //這一部分比較復(fù)雜,后面研究完成了,會單獨拿出來講,這里先弄清楚Xwork依賴注入的實現(xiàn)步驟就可以了

      ContainerProperties props = new ContainerProperties();

      ContainerBuilder builder = new ContainerBuilder();

      for(final ContainerProvider containerProvider : providers)

      {

      //循環(huán)調(diào)用ConfigurationProvider的init和register方法,明白了吧,在這里統(tǒng)一循環(huán)調(diào)用

      containerProvider.init(this);

      containerProvider.register(builder, props);

      }

      props.setConstants(builder);

      //注入依賴關(guān)系,在這里并不產(chǎn)生實例

      builder.factory(Configuration.class, new Factory(){

      public Configuration create(Context context)throws Exception {

      return DefaultConfiguration.this;

      }

      });

      ActionContext oldContext = ActionContext.getContext();

      try {

      // Set the bootstrap container for the purposes of factory creation

      Container bootstrap = createBootstrapContainer();

      setContext(bootstrap);

      //create已經(jīng)注入依賴關(guān)系的Container

      container = builder.create(false);

      setContext(container);

      objectFactory = container.getInstance(ObjectFactory.class);

      // Process the configuration providers first

      for(final ContainerProvider containerProvider : providers)

      {

      if(containerProvider instanceof PackageProvider){

      container.inject(containerProvider);

      //調(diào)用PackageProvider的loadPackages()方法,這里主要是針對XmlConfigurationProvider和StrutsXmlConfigurationProvider

      ((PackageProvider)containerProvider).loadPackages();

      packageProviders.add((PackageProvider)containerProvider);

      }

      }

      // Then process any package providers from the plugins

      Set

      packageProviderNames

      = container.getInstanceNames(PackageProvider.class);

      if(packageProviderNames!= null){

      for(String name : packageProviderNames){

      PackageProvider

      provider.init(this);

      provider.loadPackages();

      packageProviders.add(provider);

      }

      }

      rebuildRuntimeConfiguration();

      } finally {

      if(oldContext == null){

      ActionContext.setContext(null);

      }

      }

      return packageProviders;

      }

      Dispatcher已經(jīng)在之前講過,這就好辦了。FilterDispatcher是Struts2的核心控制器,首先看一下init()方法。

      public void init(FilterConfig filterConfig)throws ServletException {

      try {

      this.filterConfig = filterConfig;

      initLogging();

      //創(chuàng)建dispatcher,前面都已經(jīng)講過啰

      dispatcher = createDispatcher(filterConfig);

      dispatcher.init();

      //注入將FilterDispatcher中的變量通過container注入,如下面的staticResourceLoader

      dispatcher.getContainer().inject(this);

      //StaticContentLoader在BeanSelectionProvider中已經(jīng)被注入了依賴關(guān)系:DefaultStaticContentLoader

      //可以在struts-default.xml中的可以找到

      staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));

      } finally {

      provider

      = container.getInstance(PackageProvider.class, name);

      ActionContext.setContext(null);

      }

      }

      public void init(FilterConfig filterConfig)throws ServletException {

      try {

      this.filterConfig = filterConfig;

      initLogging();

      //創(chuàng)建dispatcher,前面都已經(jīng)講過啰

      dispatcher = createDispatcher(filterConfig);

      dispatcher.init();

      //注入將FilterDispatcher中的變量通過container注入,如下面的staticResourceLoader

      dispatcher.getContainer().inject(this);

      //StaticContentLoader在BeanSelectionProvider中已經(jīng)被注入了依賴關(guān)系:DefaultStaticContentLoader

      //可以在struts-default.xml中的可以找到

      staticResourceLoader.setHostConfig(new FilterHostConfig(filterConfig));

      } finally {

      ActionContext.setContext(null);

      }

      }

      //下面來看DefaultStaticContentLoader的setHostConfig

      public void setHostConfig(HostConfig filterConfig){

      //讀取初始參數(shù)

      pakages,調(diào)用

      parse(),解析成類似/org/apache/struts2/static,/template的數(shù)組

      String param = filterConfig.getInitParameter(“packages”);

      //“org.apache.struts2.static org.apache.struts2.interceptor.debugging static”

      String packages = getAdditionalPackages();

      if(param!= null){

      packages = param + “ ” + packages;

      }

      this.pathPrefixes = parse(packages);

      initLogging(filterConfig);

      }

      template //下面來看DefaultStaticContentLoader的setHostConfig

      public void setHostConfig(HostConfig filterConfig){

      //讀取初始參數(shù)

      pakages,調(diào)用

      parse(),解析成類似/org/apache/struts2/static,/template的數(shù)組

      String param = filterConfig.getInitParameter(“packages”);

      //“org.apache.struts2.static org.apache.struts2.interceptor.debugging static”

      String packages = getAdditionalPackages();

      if(param!= null){

      packages = param + “ ” + packages;

      }

      this.pathPrefixes = parse(packages);

      initLogging(filterConfig);

      }

      現(xiàn)在回去doFilter的方法,每當有一個Request,都會調(diào)用這些Filters的doFilter方法

      public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {

      HttpServletRequest request =(HttpServletRequest)req;

      HttpServletResponse response =(HttpServletResponse)res;

      ServletContext servletContext = getServletContext();

      String timerKey = “FilterDispatcher_doFilter: ”;

      try {

      // FIXME: this should be refactored better to not duplicate work with the action invocation

      //先看看ValueStackFactory所注入的實現(xiàn)類OgnlValueStackFactory

      //new OgnlValueStack

      ValueStack

      stack

      = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

      ActionContext ctx = new ActionContext(stack.getContext());

      ActionContext.setContext(ctx);

      template

      UtilTimerStack.push(timerKey);

      //如果是multipart/form-data就用MultiPartRequestWrapper進行包裝

      //MultiPartRequestWrapper

      StrutsRequestWrapper的子類,兩者都是HttpServletRequest實現(xiàn)

      //此時在MultiPartRequestWrapper中就會把Files給解析出來,用于文件上傳

      //所有request都會StrutsRequestWrapper進行包裝,StrutsRequestWrapper是可以訪問ValueStack

      //下面是參見Dispatcher的wrapRequest

      // String content_type = request.getContentType();

      //if(content_type!= null&&content_type.indexOf(“multipart/form-data”)!=-1){

      //MultiPartRequest multi =getContainer().getInstance(MultiPartRequest.class);

      //request MultiPartRequestWrapper(multi,request,getSaveDir(servletContext));

      //} else {

      //

      request = new StrutsRequestWrapper(request);

      // }

      request = prepareDispatcherAndWrapRequest(request, response);

      ActionMapping mapping;

      try {

      //根據(jù)url取得對應(yīng)的Action的配置信息

      //看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存儲在 ActionMapping對象中

      mapping

      =

      actionMapper.getMapping(request, dispatcher.getConfigurationManager());

      } catch(Exception ex){

      log.error(“error getting ActionMapping”, ex);

      dispatcher.sendError(request,return;

      }

      //如果找不到對應(yīng)的action配置,則直接返回。比如你輸入***.jsp等等

      //這兒有個例外,就是如果path是以“/struts”開頭,則到初始參數(shù)packages配置的包路徑去查找對應(yīng)的靜態(tài)資源并輸出到頁面流中,當然.class文件除外。如果再沒有則跳轉(zhuǎn)到

      response,servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);

      =new 404

      if(mapping == null){

      // there is no action in this request, should we look for a static resource?

      String resourcePath = RequestUtils.getServletPath(request);

      if(“".equals(resourcePath)&& null!= request.getPathInfo()){

      resourcePath = request.getPathInfo();

      }

      if(staticResourceLoader.canHandle(resourcePath)){

      // 在DefaultStaticContentLoader

      :return

      serveStatic

      &&(resourcePath.startsWith(”/struts“)|| resourcePath.startsWith(”/static“));

      staticResourceLoader.findStaticResource(resourcePath, response);

      } else {

      // this is a normal request, let it pass through

      chain.doFilter(request, response);

      }

      // The framework did its job here

      return;

      }

      //正式開始Action的方法

      dispatcher.serviceAction(request, response, servletContext, mapping);

      } finally {

      try {

      ActionContextCleanUp.cleanUp(req);

      } finally {

      UtilTimerStack.pop(timerKey);

      }

      }

      }

      public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {

      HttpServletRequest request =(HttpServletRequest)req;

      request,HttpServletResponse response =(HttpServletResponse)res;

      ServletContext servletContext = getServletContext();

      String timerKey = ”FilterDispatcher_doFilter: “;

      try {

      // FIXME: this should be refactored better to not duplicate work with the action invocation

      //先看看ValueStackFactory所注入的實現(xiàn)類OgnlValueStackFactory

      //new OgnlValueStack

      ValueStack

      stack

      = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();

      ActionContext ctx = new ActionContext(stack.getContext());

      ActionContext.setContext(ctx);

      UtilTimerStack.push(timerKey);

      //如果是multipart/form-data就用MultiPartRequestWrapper進行包裝

      //MultiPartRequestWrapperHttpServletRequest實現(xiàn)

      //此時在MultiPartRequestWrapper中就會把Files給解析出來,用于文件上傳

      //所有request都會StrutsRequestWrapper進行包裝,StrutsRequestWrapper是可以訪問ValueStack

      //下面是參見Dispatcher的wrapRequest

      // String content_type = request.getContentType();

      //if(content_type!= null&&content_type.indexOf(”multipart/form-data“)!=-1){

      //MultiPartRequest multi =getContainer().getInstance(MultiPartRequest.class);

      //request MultiPartRequestWrapper(multi,request,getSaveDir(servletContext));

      //} else {

      //

      request = new StrutsRequestWrapper(request);

      // }

      request = prepareDispatcherAndWrapRequest(request, response);

      ActionMapping mapping;

      try {

      =new

      StrutsRequestWrapper的子類,兩者都是

      //根據(jù)url取得對應(yīng)的Action的配置信息

      //看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存儲在 ActionMapping對象中

      mapping

      } catch(Exception ex){

      log.error(”error getting ActionMapping“, ex);

      dispatcher.sendError(request,return;

      }

      //如果找不到對應(yīng)的action配置,則直接返回。比如你輸入***.jsp等等

      //這兒有個例外,就是如果path是以“/struts”開頭,則到初始參數(shù)packages配置的包路徑去查找對應(yīng)的靜態(tài)資源并輸出到頁面流中,當然.class文件除外。如果再沒有則跳轉(zhuǎn)到404

      if(mapping == null){

      // there is no action in this request, should we look for a static resource?

      String resourcePath = RequestUtils.getServletPath(request);

      if(”“.equals(resourcePath)&& null!= request.getPathInfo()){

      resourcePath = request.getPathInfo();

      }

      if(staticResourceLoader.canHandle(resourcePath)){

      // 在DefaultStaticContentLoader

      :return

      serveStatic

      &&(resourcePath.startsWith(”/struts“)|| resourcePath.startsWith(”/static“));

      staticResourceLoader.findStaticResource(resourcePath, response);

      } else {

      // this is a normal request, let it pass through

      chain.doFilter(request, response);

      }

      // The framework did its job here

      return;

      }

      request,response,servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);

      =

      actionMapper.getMapping(request, dispatcher.getConfigurationManager());

      //正式開始Action的方法

      dispatcher.serviceAction(request, response, servletContext, mapping);

      } finally {

      try {

      ActionContextCleanUp.cleanUp(req);

      } finally {

      UtilTimerStack.pop(timerKey);

      }

      }

      }

      //下面是ActionMapper接口的實現(xiàn)類 DefaultActionMapper的getMapping()方法的源代碼:

      public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

      ActionMapping mapping = new ActionMapping();

      String uri = getUri(request);//得到請求路徑的URI,如:testAtcion.action或testAction.do

      int indexOfSemicolon = uri.indexOf(”;“);//修正url的帶;jsessionid 時找不到而且的bug

      uri =(indexOfSemicolon >-1)? uri.substring(0, indexOfSemicolon): uri;

      uri = dropExtension(uri, mapping);//刪除擴展名,默認擴展名為action

      if(uri == null){

      return null;

      }

      parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace

      handleSpecialParameters(request, mapping);//去掉重復(fù)參數(shù)

      //如果Action的name沒有解析出來,直接返回

      if(mapping.getName()== null){

      returnnull;

      }

      //下面處理形如testAction!method格式的請求路徑

      if(allowDynamicMethodCalls){

      // handle ”name!method“ convention.String name = mapping.getName();

      int exclamation = name.lastIndexOf(”!“);//!是Action名稱和方法名的分隔符

      if(exclamation!=-1){

      mapping.setName(name.substring(0, exclamation));//提取左邊為name

      mapping.setMethod(name.substring(exclamation + 1));//提取右邊的method

      }

      }

      return mapping;

      }

      //下面是ActionMapper接口的實現(xiàn)類 DefaultActionMapper的getMapping()方法的源代碼:

      public ActionMapping getMapping(HttpServletRequest request,ConfigurationManager configManager){

      ActionMapping mapping = new ActionMapping();

      String uri = getUri(request);//得到請求路徑的URI,如:testAtcion.action或testAction.do

      int indexOfSemicolon = uri.indexOf(”;“);//修正url的帶;jsessionid 時找不到而且的bug

      uri =(indexOfSemicolon >-1)? uri.substring(0, indexOfSemicolon): uri;

      uri = dropExtension(uri, mapping);//刪除擴展名,默認擴展名為action

      if(uri == null){

      return null;

      }

      parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace

      handleSpecialParameters(request, mapping);//去掉重復(fù)參數(shù)

      //如果Action的name沒有解析出來,直接返回

      if(mapping.getName()== null){

      returnnull;

      }

      //下面處理形如testAction!method格式的請求路徑

      if(allowDynamicMethodCalls){

      // handle ”name!method“ convention.String name = mapping.getName();

      int exclamation = name.lastIndexOf(”!“);//!是Action名稱和方法名的分隔符

      if(exclamation!=-1){

      mapping.setName(name.substring(0, exclamation));//提取左邊為name

      mapping.setMethod(name.substring(exclamation + 1));//提取右邊的method

      }

      }

      return mapping;

      }

      從代碼中看出,getMapping()方法返回ActionMapping類型的對象,該對象包含三個參數(shù):Action的name、namespace和要調(diào)用的方法method。

      如果getMapping()方法返回ActionMapping對象為null,則FilterDispatcher認為用戶請求不是Action,自然另當別論,F(xiàn)ilterDispatcher會做一件非常有意思的事:如果請求以/struts開頭,會自動查找在web.xml文件中配置的 packages初始化參數(shù),就像下面這樣:

      struts2

      org.apache.struts2.dispatcher.FilterDispatcher

      packages

      com.lizanhong.action

      struts2

      org.apache.struts2.dispatcher.FilterDispatcher

      packages

      com.lizanhong.action

      FilterDispatcher會將com.lizanhong.action包下的文件當作靜態(tài)資源處理,即直接在頁面上顯示文件內(nèi)容,不過會忽略擴展名為class的文件。比如在com.lizanhong.action包下有一個aaa.txt的文本文件,其內(nèi)容為“中華人民共和國”,訪問

      http://localhost:8081/Struts2Demo/struts/aaa.txt時會輸出txt中的內(nèi)容

      FilterDispatcher.findStaticResource()方法

      protectedvoid findStaticResource(String

      name,HttpServletRequest

      request, HttpServletResponse response)throws IOException {

      if(!name.endsWith(”.class“)){//忽略class文件

      //遍歷packages參數(shù)

      for(String pathPrefix : pathPrefixes){

      InputStream is = findInputStream(name, pathPrefix);//讀取請求文件流

      if(is!= null){

      ...// set the content-type header

      String contentType = getContentType(name);//讀取內(nèi)容類型

      if(contentType!= null){

      response.setContentType(contentType);//重新設(shè)置內(nèi)容類型

      }

      ...try {

      //將讀取到的文件流以每次復(fù)制4096個字節(jié)的方式循環(huán)輸出

      copy(is, response.getOutputStream());

      } finally {

      is.close();

      }

      return;

      }

      }

      }

      }

      protectedvoid findStaticResource(String

      name,HttpServletRequest

      request, HttpServletResponse response)throws IOException {

      if(!name.endsWith(”.class“)){//忽略class文件

      //遍歷packages參數(shù)

      for(String pathPrefix : pathPrefixes){

      InputStream is = findInputStream(name, pathPrefix);//讀取請求文件流

      if(is!= null){

      ...// set the content-type header

      String contentType = getContentType(name);//讀取內(nèi)容類型

      if(contentType!= null){

      response.setContentType(contentType);//重新設(shè)置內(nèi)容類型

      }

      ...try {

      //將讀取到的文件流以每次復(fù)制4096個字節(jié)的方式循環(huán)輸出

      copy(is, response.getOutputStream());

      } finally {

      is.close();

      }

      return;

      }

      }

      }

      }

      如果用戶請求的資源不是以/struts開頭——可能是.jsp文件,也可能是.html文件,則通過過濾器鏈繼續(xù)往下傳送,直到到達請求的資源為止。

      如果getMapping()方法返回有效的ActionMapping對象,則被認為正在請求某個Action,將調(diào)用 Dispatcher.serviceAction(request, response, servletContext, mapping)方法,該方法是處理Action的關(guān)鍵所在。

      下面就來看serviceAction,這又回到全局變量dispatcher中了

      //Load Action class for mapping and invoke the appropriate Action method, or go directly to the Result.public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping)throws ServletException {

      //createContextMap方法主要把Application、Session、Request的key value值拷貝到Map中

      Map 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();

      String name = mapping.getName();

      String method = mapping.getMethod();

      Configuration config = configurationManager.getConfiguration();

      //創(chuàng)建一個Action的代理對象,ActionProxyFactory是創(chuàng)建ActionProxy的工廠

      //參考實現(xiàn)類:DefaultActionProxy和DefaultActionProxyFactory

      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!

      //如果是Result,則直接轉(zhuǎn)向,關(guān)于Result,ActionProxy,ActionInvocation下一講中再分析

      if(mapping.getResult()!= null){

      Result result = mapping.getResult();

      result.execute(proxy.getInvocation());

      } else {

      //執(zhí)行Action

      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){

      LOG.error(”Could not find action or result“, e);

      }

      else {

      LOG.warn(”Could not find action or result“, e);

      }

      sendError(request, HttpServletResponse.SC_NOT_FOUND, e);

      } catch(Exception e){

      sendError(request,} finally {

      UtilTimerStack.pop(timerKey);

      }

      } 下面開始講一下主菜ActionProxy了.在這之前最好先去了解一下動態(tài)Proxy的基本知識.ActionProxy是Action的一個代理類,也就是說Action的調(diào)用是通過ActionProxy實現(xiàn)的,其實就是調(diào)用了ActionProxy.execute()方法,而該方法又調(diào)用了ActionInvocation.invoke()方法。歸根到底,最后調(diào)用的是DefaultActionInvocation.invokeAction()方法。DefaultActionInvocation()->init()->createAction()。

      最后

      調(diào)

      用ActionProxy.exute()-->ActionInvocation.invoke()-->Intercepter.intercept()-->ActionInvocation.invokeActionOnly()-->invokeAction()這里的步驟是先由ActionProxyFactory創(chuàng)建ActionInvocation和ActionProxy.public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext){

      ActionInvocation inv = new DefaultActionInvocation(extraContext, true);

      container.inject(inv);

      return }

      public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext){

      createActionProxy(inv,namespace,actionName,methodName, executeResult, cleanupContext);

      response,context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);

      response,context,ActionInvocation inv = new DefaultActionInvocation(extraContext, true);

      container.inject(inv);

      return }

      下面先看DefaultActionInvocation的init方法

      public void init(ActionProxy proxy){

      this.proxy = proxy;

      Map contextMap = createContextMap();

      // Setting this so that other classes, like object factories, can use the ActionProxy and other

      // contextual information to operate

      ActionContext actionContext = ActionContext.getContext();

      if(actionContext!= null){

      actionContext.setActionInvocation(this);

      }

      //創(chuàng)建Action,struts2中每一個Request都會創(chuàng)建一個新的Action

      createAction(contextMap);

      if(pushAction){

      stack.push(action);

      contextMap.put(”action“, action);

      }

      invocationContext = new ActionContext(contextMap);

      invocationContext.setName(proxy.getActionName());

      // get a new List so we don't get problems with the iterator if someone changes the list

      List

      interceptorList

      =

      new ArrayList(proxy.getConfig().getInterceptors());

      interceptors = interceptorList.iterator();

      createActionProxy(inv,namespace,actionName,methodName, executeResult, cleanupContext);

      }

      protected void createAction(Map contextMap){

      // load action

      String timerKey = ”actionCreate: “ + proxy.getActionName();

      try {

      UtilTimerStack.push(timerKey);

      //默認為SpringObjectFactory:struts.objectFactory=spring.這里非常巧妙,在struts.properties中可以重寫這個屬性

      //在前面BeanSelectionProvider中通過配置文件為ObjectFactory設(shè)置實現(xiàn)類

      //這里以Spring為例,這里會調(diào)到SpringObjectFactory的buildBean方法,可以通過ApplicationContext的getBean()方法得到Spring的Bean

      action

      =

      objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);

      } catch(InstantiationException e){

      throw new

      XWorkException(”Unable

      to

      intantiate

      Action!“,e, proxy.getConfig());

      } catch(IllegalAccessException e){

      throw new XWorkException(”Illegal access to constructor, is it public?", e, proxy.getConfig());

      } catch(Exception e){

      ...} finally {

      UtilTimerStack.pop(timerKey);

      }

      if(actionEventListener!= null){

      action = actionEventListener.prepare(action, stack);

      }

      }

      //SpringObjectFactory

      public Object buildBean(String beanName, Map extraContext, boolean injectInternal)throws Exception {

      Object o = null;

      try {

      //SpringObjectFactory

      web.xml

      中的

      第三篇:實驗三 Struts2框架編程-實驗報告紙

      南京信息工程大學(xué) 實驗(實習(xí))報告

      實驗(實習(xí))名稱 Struts2框架編程 實驗(實習(xí))日期 得分 指導(dǎo)教師 院 計軟 專業(yè) 計科 年級 2013級 班次 3 姓名 張文嬌 學(xué)號 20131308081

      1.實驗?zāi)康模?/p>

      1)掌握Struts2框架和工作流程。2)熟悉Struts標簽庫的使用。

      3)掌握Struts 2攔截器的原理,并能進行相關(guān)設(shè)置和編程。4)了解和掌握文件上傳等功能實現(xiàn)

      2.實驗內(nèi)容:

      1)采用Struts2框架,創(chuàng)建三個JSP頁面(hello.jsp、welcome.jsp)和一個Action實現(xiàn)類(StrutsAction),并對web.xml和Struts.xml進行必要配置,實現(xiàn)用戶登錄功能的處理。(參考教材3.1節(jié))

      2)采用Struts2相關(guān)技術(shù),實現(xiàn)“學(xué)生綜合管理系統(tǒng)”的“添加學(xué)生信息”功能(具體需求詳見教材3.7所述)

      3.實驗步驟

      {對每個實驗題目進行簡要步驟描述,包括源碼和實驗結(jié)果截圖} 1)

      1.啟動MyEclips 8.5 2.創(chuàng)建web project項目命名為FirstStruts2 3.添加支持包 4.配置web.xml struts2.0 org.apache.struts2.dispatcher.FilterDispatcher struts2.0 /*

      5.在工程中創(chuàng)建LoginAction.jsp import dao.CustomerDAO;public class LoginAction {

      private String name;private String password;/**在此方法里實現(xiàn)業(yè)務(wù)邏輯處理*/ public String execute()throws Exception {

      CustomerDAO dao=new CustomerDAO();boolean boo=dao.check(name, password);if(boo)return “success”;

      } else return “error”;public String getName(){ return name;} public void setName(String name){ this.name = name;} public String getPassword(){ return password;} public void setPassword(String password){this.password = password;} } 6.配置struts.xml文件

      /success.jsp /error.jsp 7.創(chuàng)建login.jsp

      用戶名:
      密碼:

      第四篇:struts2框架的6個配置文件

      Struts2的6個配置文件,分別是struts-default.xml,default.properties,struts-plugin.xml,struts.xml,struts.properties,web.xml

      1、struts-default.xml,里面放置的是struts2框架的核心東西,如bean類,package包,result type,interceptor攔截器等

      2、default.properties,properties類型的文件里面放置的是鍵值對,key和value,主要是對一些常量進行設(shè)定。

      3、struts-plugin.xml,與第三方插件進行整合時需要使用的配置文件。如我們和spring進行整合時,就需要使用到struts-spring-plugin.xml這個配置文件

      4、struts.xml,需要我們程序員在src目錄下手動創(chuàng)建,在這個里面也可以對常量進行設(shè)定,使用的是constant標簽,包含name和value屬性。

      5、struts.properties,這里也是對常量進行設(shè)定

      6、web.xml,這里設(shè)定struts2的啟動項,使用的是filter和filter-mapping標簽,也可以進行常量的設(shè)定,在filter標簽里使用init-param標簽。但是我們一般不再這里設(shè)定。

      這里有4個配置文件,可以對常量進行設(shè)定。分別是default.properties,struts.xml,struts.properties,web.xml。他們的優(yōu)先級順序是web.xml優(yōu)先級最高,其次是struts.properties,struts.xml,最后是default.properties。我們最主要進行學(xué)習(xí)的就是struts.xml,其他的作為了解內(nèi)容就可以了。

      第五篇:Struts2介紹

      Struts2集成指南

      關(guān)于Struts2 Struts是Apache軟件基金會(ASF)贊助的一個開源項目。它最初是Jakarta項目中的一個子項目,并在2004年3月成為ASF的頂級項目。它通過采用Java Servlet/JSP技術(shù),實現(xiàn)了基于Java EE Web應(yīng)用的Model-View-Controller〔MVC〕設(shè)計模式的應(yīng)用框架〔Web Framework〕,是MVC經(jīng)典設(shè)計模式中的一個經(jīng)典產(chǎn)品。

      Struts,a history 在Java EE的Web應(yīng)用發(fā)展的初期,除了使用Servlet技術(shù)以外,普遍是在JavaServer Pages(JSP)的源代碼中,采用HTML與Java代碼混合的方式進行開發(fā)。因為這兩種方式不可避免的要把表現(xiàn)與業(yè)務(wù)邏輯代碼混合在一起,都給前期開發(fā)與后期維護帶來巨大的復(fù)雜度。為了擺脫上述的約束與局限,把業(yè)務(wù)邏輯代碼從表現(xiàn)層中清晰的分離出來,2000年,Craig McClanahan采用了MVC的設(shè)計模式開發(fā)Struts。后來該框架產(chǎn)品一度被認為是最廣泛、最流行JAVA的WEB應(yīng)用框架。

      Craig McClanahan 2006年,WebWork與Struts這兩個優(yōu)秀的Java EE Web框架(Web Framework〕的團體,決定合作共同開發(fā)一個新的,整合了WebWork與Struts優(yōu)點,并且更加優(yōu)雅、擴展性更強的框架,命名為“Struts 2”,原Struts的1.x版本產(chǎn)品稱為“Struts 1”。

      至此,Struts項目并行提供與維護兩個主要版本的框架產(chǎn)品——Struts 1與Struts 2。Struts1 vs.Struts2 侵入性

      Struts 1 在編程方面是面向抽象類編程,而不是面向接口編程。Struts 1要求自定義Action 類繼承一個特定的抽象基類Action。另一方面,Struts 1的 Action 依賴于 Servlet API,因為Struts 1 Action 的execute 方法中有HttpServletRequest 和HttpServletResponse 方法。例如 e.g.public class LogonAction extends Action {

      public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response){

      } }

      Struts 2 Action 類可以實現(xiàn)一個Action接口,也可以實現(xiàn)其他接口,甚至不實現(xiàn)任何接口。這使得可選的和定制的服務(wù)成為可能。e.g.public class ExampleAction {

      public String doSomething(){

      return “success”;} }

      線程模式

      Struts 1 Action類 是單例模式并且必須是線程安全的,因為在web容器中,僅有Action類 的一個實例來處理所有的請求。

      Struts2 Web容器為每一個請求產(chǎn)生一個Action類實例,因此沒有線程安全問題??蓽y試性

      Struts1 由于對Servlet API的依賴,使得針對于自定義Action類的測試變得復(fù)雜。

      Struts2 由于自定義Action可以為POJO,所以可以向測試一個POJO一樣來測試Action類。

      請求參數(shù)封裝

      Struts1 使用ActionForm 對象封裝用戶的請求參數(shù),所有的 ActionForm 必須繼承一個基類:ActionForm。普通的JavaBean 不能用作ActionForm,并且需要在配置文件中定義ActionForm。e.g.public class LogonForm extends ActionForm {

      private String userpassword;

      private String username;}

      Struts2 直接使用Action屬性來封裝用戶請求屬性,避免了開發(fā)者需要大量開發(fā)ActionForm類的煩瑣,實際上,這些屬性還可以是包含子屬性的 Rich對象類型。e.g.public class ExampleAction {

      private String responseMessage;private String requestMessage;

      public String getResponseMessage(){

      return responseMessage;}

      public void setResponseMessage(String responseMessage){

      this.responseMessage = responseMessage;}

      public String getRequestMessage(){

      return requestMessage;

      } } public void setRequestMessage(String requestMessage){ } this.requestMessage = requestMessage;public String doSomething(){

      } setMessage(“Hi, ” + getRequestMessage());return “success”;EL Struts1 整合了 JSTL,因此可以使用JSTL 表達式語言。JSTL有基本對象圖遍歷,但在對集合和索引屬性的支持上則功能不強。在向視圖綁定值時,Struts1 使用標準JSP 機制把對象綁定到視圖頁面。

      Struts2 Struts 2 可以使用JSTL,但它整合了一種更強大和靈活的表達式語言:OGNL(Object Graph Notation Language),因此,Struts 2 下的表達式語言功能更加強大。在向視圖綁定值時,Struts2 使用“ValueStack ”技術(shù),使標簽庫能夠訪問值,而不需要把對象和視圖頁面綁定在一起。

      校驗框架

      Struts1 Struts1 支持在 ActionForm 重寫validate 方法中手動校驗,或者通過整合 Commons-validator 框架來完成數(shù)據(jù)校驗。

      Struts2 Struts 2 支持通過重寫validate方法進行校驗,也支持整合XWork 校驗框架進行校驗。Struts2 architacture

      名詞約定

      凡是代碼、配置文件、IDE中出現(xiàn)的名詞,均采用英文原稱。

      Roadmap 本文檔的目標是,幫助讀者在Eclipse中將Struts2集成至一個嶄新的Dynamic Web Project。集成步驟大致如下:配置Struts2的代碼環(huán)境-> 在web.xml中加入Struts2功能-> 測試Struts2。文檔目標達成的標志是:頁面請求能夠通過Struts2的Action Mapping成功轉(zhuǎn)發(fā),并且基于Java的Struts2驗證框架能夠生效。

      集成步驟

      引入Struts2相關(guān)的jar文件

      Struts2 jars ? ? ? ? ? ? ? ? ? ? commons-fileupload-1.2.2.jar commons-io-2.1.jar commons-lang-2.4.jar commons-logging-1.1.1.jar freemarker-2.3.16.jar javassist.jar jstl-1.2.jar ognl-3.0.1.jar struts2-core-2.2.3.jar xwork-core-2.2.3.jar 加入build path 將以上10個jar文件,拷貝至WebContent/WEB-INF/lib下:

      對于Web Dynamic Project,一般情況下,當你向lib目錄下copy了jar文件,eclipse會自動將jar文件加入build path下的名為Web App Libraries的Library。請確認在工程下出現(xiàn)了名為Web App Libraries的Library。如果有,說明這些jar文件已經(jīng)被添加至build path了:

      如果在工程目錄下找不到名為Web App Libraries的Library,說明jar文件沒有被添加至build path,需要進行手動添加。首先進入build path設(shè)置界面,選中Libraries 頁,并點擊Add JARs:

      在JAR Selection窗口中,選中l(wèi)ib下所有的jar文件。選中后點擊OK:

      你將看到被選中的jar文件已經(jīng)被添加至build path:

      在工程中會出現(xiàn)一個名為Referenced Libraries的Libraries。這說明jar文件已經(jīng)被添加至build path:

      以上兩種方法都可以將jar文件添加至build path,它們的效果是一樣的。

      配置web.xml 添加filter 在web.xml中添加一個filter:

      struts2

      org.apache.struts2.dispatcher.FilterDispatcher

      filter-name表示filter的名字,你可以任意決定這個名字。filter-class表示使用哪個類作為filter,從這個類的全稱來判斷,可以發(fā)現(xiàn)FilterDispatcher是Struts2提供的一個類。它是Struts2轉(zhuǎn)發(fā)請求的起點。在web.xml中添加一個filter-mapping:

      struts2

      /*

      filter-mapping用來映射url和filter的映射關(guān)系。filter-name表示filter的名字,這個名字必須和之前filter聲明中的filter-name一致。url-pattern表示哪些格式的url會被此filter濾中。/*表示在此web應(yīng)用域名下,所有的地址都會被filter濾中,換言之,所有的http請求都會通過Struts2進行轉(zhuǎn)發(fā)。

      filter的作用

      通過以上的配置,F(xiàn)ilterDispatcher和url與filter-name聯(lián)系在了一起。

      由于在web容器中注冊了FilterDispatcher這個filter,Struts2可以收到所有http://localhost:8080/tyland-b2b 的http請求。隨后,F(xiàn)ilterDispatcher會根據(jù)我們定義的action-mapping規(guī)則,將請求分發(fā)到指定的action類以及它的攔截器棧。最后,Struts2按照action-mapping規(guī)則,將后臺計算的結(jié)果返回給指定頁面?;\統(tǒng)地來說,Struts2就是這樣工作的,所以說,F(xiàn)ilterDispatcher是Struts2工作的入口。

      編寫代碼,測試Struts2 Struts2的環(huán)境已經(jīng)配置好了,基于action-mapping的轉(zhuǎn)發(fā)機制已經(jīng)可以運行了。為了證明這一點,請編寫一些測試jsp頁面和java代碼。

      在編寫代碼的過程中,請確保代碼文件的位置如下圖所示:

      代碼清單如下:

      Java代碼

      UserVO.java package com.tyland.b2b.vo;

      // 一個Value Object(Data Model),用來存放用戶名、密碼 public class UserVO {

      private String username;private String password;

      // 成員變量password的getter方法。

      // 在Strtus2中,用來在頁面和服務(wù)器間傳值的Value Object必須有g(shù)etter方法

      public String getPassword(){

      return password;

      } } // 成員變量password的setter方法。

      // 在Strtus2中,用來在頁面和服務(wù)器間傳值的Value Object必須有setter方法 public void setPassword(String password){ } this.password = password;// 同password

      public String getUsername(){ } return username;// 同password

      public void setUsername(String username){ } this.username = username;BaseAction.java package com.tyland.b2b.web.base;

      import com.opensymphony.xwork2.ActionSupport;

      // 為了代碼的靈活性和可擴展性,請聲明一個BaseAction基類

      // BaseAction繼承Struts2的ActionSupport,因為我們想使用Struts2的一些額外幫助。// 對于ActionSupport的繼承不是必須的

      public class BaseAction extends ActionSupport {

      private static final long serialVersionUID = ***74952195L;} UserAction.java package com.tyland.b2b.web;

      import com.tyland.b2b.vo.UserVO;import com.tyland.b2b.web.base.BaseAction;

      // 自定義的Action類,繼承BaseAction // 由于繼承了ActionSupport,我們可以使用Struts2默認的action方法execute()// 由于繼承了ActionSupport,我們可以使用Struts2默認的校驗方法validate()public class UserAction extends BaseAction {

      private static final long serialVersionUID =-7***3684190L;

      // 用來在頁面和服務(wù)器之間傳遞用戶名、密碼的Value Object。變量名任意。

      private UserVO userVO;

      執(zhí)行。// 用來在頁面和服務(wù)器之間傳遞message變量。名稱任意。private String message;//用來在頁面和服務(wù)器之間傳遞sayHiTo變量。名稱任意。private String sayHiTo;// 用來傳值的變量必須有g(shù)etter方法 public UserVO getUserVO(){ return userVO;}

      //用來傳值的變量必須有setter方法

      public void setUserVO(UserVO userVO){ } this.userVO = userVO;public String getMessage(){ } return message;public void setMessage(String message){ } this.message = message;public String getSayHiTo(){ } return sayHiTo;public void setSayHiTo(String sayHiTo){ } this.sayHiTo = sayHiTo;// Override聲明說明這個方法復(fù)寫或?qū)崿F(xiàn)了父類或接口方法。

      // 如action-mapping中不顯示指定別的方法,struts2會將execute()作為默認的action方法// 返回的SUCCESS常量,來自ActionSupport,值為“success”。

      // action-mapping會根據(jù)不同的返回值采取不同的轉(zhuǎn)發(fā)或頁面跳轉(zhuǎn)動作。@Override

      public String execute()throws Exception {

      } System.out.println(“******execute******”);System.out.println(userVO.getUsername()+ “ logins”);return SUCCESS;

      // 在Struts2執(zhí)行execute()之前,會先執(zhí)行validateExecute()進行用戶輸入驗證 // 這個方法名必須符合Struts2驗證框架所規(guī)定的命名規(guī)范 public void validateExecute(){

      }

      } System.out.println(“******validateExecute******” + userVO.getUsername());if(null == userVO.getUsername()|| userVO.getUsername().length()< 5){ this.addFieldError(“username”, “USERNAME ERROR”);} if(null == userVO.getPassword()|| userVO.getPassword().length()< 5){ this.addFieldError(“password”, “PASSWORD ERROR”);} // 一個自定義方法。通過在action-mapping中的設(shè)置,可以實現(xiàn)使用POJO的自定義服務(wù)配置 public String sayHi()throws Exception {

      } System.out.println(“say hi to ” + getSayHiTo());return SUCCESS;// 符合驗證框架命名規(guī)范的、真對于sayHi()的驗證方法 public void validateSayHi(){

      } System.out.println(“******validateSayHi******” + getSayHiTo());if(null == getSayHiTo()|| getSayHiTo().length()< 5){ this.addFieldError(“sayHiTo”, “SAYHITO ERROR”);} ExampleAction.java package com.tyland.b2b.web;

      import com.tyland.b2b.web.base.BaseAction;

      public class ExampleAction extends BaseAction {

      private static final long serialVersionUID =-***7281L;

      private String message;private String sayHiTo;

      public String getMessage(){

      return message;}

      public void setMessage(String message){

      this.message = message;}

      public String getSayHiTo(){

      return sayHiTo;}

      } public void setSayHiTo(String sayHiTo){ } this.sayHiTo = sayHiTo;public String finish(){

      } System.out.println(“example finished”);setMessage(getSayHiTo());return SUCCESS;JSP代碼

      index.jsp <%@ page language=“java” contentType=“text/html;charset=UTF-8”

      pageEncoding=“UTF-8”%>

      <%@ taglib uri = “http://java.sun.com/jsp/jstl/core” prefix = “c” %>

      Hello World

      下載Struts 2框架分析word格式文檔
      下載Struts 2框架分析.doc
      將本文檔下載到自己電腦,方便修改和收藏,請勿使用迅雷等下載。
      點此處下載文檔

      文檔為doc格式


      聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻自行上傳,本網(wǎng)站不擁有所有權(quán),未作人工編輯處理,也不承擔(dān)相關(guān)法律責(zé)任。如果您發(fā)現(xiàn)有涉嫌版權(quán)的內(nèi)容,歡迎發(fā)送郵件至:645879355@qq.com 進行舉報,并提供相關(guān)證據(jù),工作人員會在5個工作日內(nèi)聯(lián)系你,一經(jīng)查實,本站將立刻刪除涉嫌侵權(quán)內(nèi)容。

      相關(guān)范文推薦

        Struts2試題

        Struts2 試題 1.struts2的執(zhí)行流程? 客戶端提交一個HttpServletRequest請求(action或JSP頁面) 請求被提交到一系列Filter過濾器,如ActionCleanUp和FiterDispatcher等 FilterDisp......

        struts2課件

        —高級軟件人才實作培訓(xùn)專家!Struts2的啟動配置在struts1.x中,struts框架是通過Servlet啟動的。在struts2中,struts框架是通過Filter啟動的。他在web.xml中的配置如下:struts2o......

        Struts2習(xí)題

        Struts2習(xí)題1 1.struts中的package的作用是什么?namespace可以為空嗎?如果namespace為空會意味著什么呢? 標識、 可以 、如果沒寫,說明該包為默認空間 2.Action 的實現(xiàn)通集成常......

        struts2源代碼分析(個人覺得非常經(jīng)典)

        本章講述Struts2的工作原理。 讀者如果曾經(jīng)學(xué)習(xí)過Struts1.x或者有過Struts1.x的開發(fā)經(jīng)驗,那么千萬不要想當然地以為這一章可以跳過。實際上Struts1.x與Struts2并無我們想象的......

        struts2復(fù)習(xí)題(含答案)

        Struts2復(fù)習(xí)題 1. 以下屬于struts2的控制器組件是: A.ActionB.ActionForm C.ActionServlet D.dispatchAction 2. 以下屬于struts2配置文件中的配置元素是:(多選) A. B. C. D......

        struts2綜合試卷范文合集

        Struts2學(xué)習(xí)增強練習(xí)課程名稱: Struts2學(xué)習(xí)增強練習(xí)考試時間 xx分鐘(閉卷■) 不定項選擇題 1. 開發(fā)struts2 web項目,需要導(dǎo)入哪些jar包 A 必須導(dǎo)入struts2 解壓lib下所有......

        struts2知識總結(jié)

        struts2知識總結(jié) 1.全局的邏輯控制器為一個過濾器,負責(zé)過濾所有的請求。該過濾器引用的API類為org.apache.struts2.disapatcher.FilterDispatcher 2.MVC:頁面請求(jsp)—......

        公司分析報告框架

        上市公司初步分析框架 一、 公司概況 公司概況性的介紹信息,包括公司名稱、所屬行業(yè)、地址、成立年份,歷史沿革等。 二、 行業(yè)分析 公司所屬的行業(yè)的競爭情況,發(fā)展前景,行業(yè)所處......