zhyiwww
          用平實的筆,記錄編程路上的點點滴滴………
          posts - 536,comments - 394,trackbacks - 0

          Struts 的資源文件時如何初始化的

          |-----------------------------------------------------------------------------------------------------|

          |????? ???????? ???????????? ?? ? 作者:zhyiwww ???????zhyiwww@163.com?????? ????????????? ???? |

          |???????????????????????????????????????????????????轉(zhuǎn)載請注明出處?????????????????????????????????????????? |
          |-----------------------------------------------------------------------------------------------------|

          分以下幾步來理解:

          [1] Web 應(yīng)用如何知道使用的是 Struts

          我們知道,在 Web 工程的 /WEB-INF/ 目錄下面,我們有兩個配置文件

          Web.xml Struts-config.xml.

          一般情況下就只有一個 web.xml 文件,如果系統(tǒng)是用了 struts 技術(shù)的話,那么就會有 struts-config.xml 文件。

          [2] 系統(tǒng)是如何啟動和初始化 struts

          Web.xml 中有這么一段代碼:

          ? < servlet >

          ??? < servlet-name > action </ servlet-name >

          ??? < servlet-class > org.apache.struts.action.ActionServlet </ servlet-class >

          ??? < init-param >

          ????? < param-name > config </ param-name >

          ????? < param-value > /WEB-INF/struts-config.xml </ param-value >

          ??? </ init-param >

          ??? < init-param >

          ????? < param-name > debug </ param-name >

          ????? < param-value > 3 </ param-value >

          ??? </ init-param >

          ??? < init-param >

          ????? < param-name > detail </ param-name >

          ????? < param-value > 3 </ param-value >

          ??? </ init-param >

          ??? < load-on-startup > 0 </ load-on-startup >

          ? </ servlet >

          ? < servlet >

          ??? < servlet-name > startThread </ servlet-name >

          ??? < servlet-class > com.cgogo.ypindex.StartThread </ servlet-class >

          ??? < init-param >

          ??? < param-name > startParam </ param-name >

          ??? < param-value > 2 </ param-value >

          ??? </ init-param >

          ??? < load-on-startup > 1 </ load-on-startup >

          ? </ servlet > ?

          ? < servlet-mapping >

          ??? < servlet-name > action </ servlet-name >

          ??? < url-pattern > *.do </ url-pattern >

          ? </ servlet-mapping >

          web.xml 中會配置 struts 的中央控制器類。 Web.xml 配置文件的初始化是由容器來實現(xiàn)載入和初始化的。如果你使用的是 tomcat 的話,那么就是由 tomcat 在啟動的時候會載入此 web.xml 文件,也就為此 web 應(yīng)用創(chuàng)建了一個 web Context, context 也就是你 Web 應(yīng)用的訪問入口。

          載入中央控制器 org.apache.struts.action.ActionServlet ,這是一個 Servlet, 那么,其就要進行 servlet 的初始化操作。此 action 是如何對 Struts 系統(tǒng)進行初始化的呢?

          [3] init()-- ActionServlet 如何初始化 Struts 系統(tǒng)?

          看一下 ActionServlet 的源代碼:

          我們知道,在一個 Servlet 中,在其啟動的時候,首先要執(zhí)行 init() 方法,那么我們先來看一下 actionServlet init() 方法的源代碼:

          ??? /**

          ???? * <p>Initialize this servlet.? Most of the processing has been factored into

          ???? * support methods so that you can override particular functionality at a

          ???? * fairly granular level.</p>

          ???? *

          ???? * @exception ServletException if we cannot configure ourselves correctly

          ???? */

          ?? ?public void init() throws ServletException {

          ?

          ??????? // Wraps the entire initialization in a try/catch to better handle

          ??????? // unexpected exceptions and errors to provide better feedback

          ??????? // to the developer

          ??????? try {

          (1)????? initInternal();

          (2)????? initOther();

          (3)????? initServlet();

          ???

          ??????????? getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);

          (4)????? initModuleConfigFactory();

          ??????????? // Initialize modules as needed

          ??????????? ModuleConfig moduleConfig = initModuleConfig("", config);

          (5)????? initModuleMessageResources(moduleConfig);

          (6)????? initModuleDataSources(moduleConfig);

          (7)????? initModulePlugIns(moduleConfig);

          ??????????? moduleConfig.freeze();

          (8)????? 初始化配置參數(shù)

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

          ?

          ??????????? // The follow error message is not retrieved from internal message

          ??????????? // resources as they may not have been able to have been

          ??????????? // initialized

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

          ??????? }???

          }

          ?

          先來看一下初始化( 1 )的部分 initInternal()

          ?

          [4] ? initInternal()-- 內(nèi)部資源文件的初始化

          initInternal() 就是實現(xiàn)內(nèi)部資源文件的初始化的,也就是轉(zhuǎn)為 Struts 系統(tǒng)本身提供的以下錯誤信息提示等文字的國際化實現(xiàn)的。我們看一下源代碼是如何實現(xiàn)的:

          ??? /**

          ???? * <p> Initialize our internal MessageResources bundle. </p>

          ???? *

          ???? * @exception ServletException if we cannot initialize these resources

          ???? */

          ??? protected void initInternal() throws ServletException {

          ?

          ??????? // : FIXME : Document UnavailableException

          ?

          ??????? try {

          ??????????? internal = MessageResources.getMessageResources( internalName );

          ??????? } catch (MissingResourceException e) {

          ??????????? log.error( "Cannot load internal resources from '" + internalName + "'" ,

          ??????????????? e);

          ??????????? throw new UnavailableException

          ??????????????? ( "Cannot load internal resources from '" + internalName + "'" );

          ??????? }

          ?

          }

          Struts 根據(jù)配置文件的名字得到一個資源文件。

          internalName 就是內(nèi)部資源文件的名稱,其在 actionServlet 中定義:

          ??? /**

          ???? * <p> The Java base name of our internal resources. </p>

          ???? * @since Struts 1.1

          ???? */

          ??? protected String internalName = "org.apache.struts.action.ActionResources" ;

          取得后的對象是一個 MessageResources 的對象,保存在 internal 中,

          ??? /**

          ???? * <p>The resources object for our internal resources.</p>

          ???? */

          ??? protected MessageResources internal = null;

          經(jīng)過此初始化后, internal 就不在是 null 了。

          至此就實現(xiàn)完成了內(nèi)部資源文件的初始化。如果出現(xiàn)了異常的話,那么系統(tǒng)就捕捉到。

          ?

          然后,系統(tǒng)就開始初始化其它的配置,即( 2 initOther();

          ?

          [5] initOther()-- 如何初始化其他的配置的?

          ??? /**

          ???? * <p>Initialize other global characteristics of the controller servlet.</p>

          ???? *

          ???? * @exception ServletException if we cannot initialize these resources

          ???? */

          ??? protected void initOther() throws ServletException {

          ?

          ??????? 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 1.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);

          ??????? }

          ?

          }

          然后就執(zhí)行( 3 initServlet();

          ?

          [6] ? initServlet()-- 如何初始化 servlet

          這個初始化主要是初始化 servlet 的,哪些 servlet 呢?就是我們在 web.xml 中配置的那些需要在 web application 初始化時就栽入系統(tǒng)的 servlet

          這是一個復(fù)雜的過程:

          ?

          我的理解:

          ?????? 這部分代碼就執(zhí)行一次,僅在初始化的時候執(zhí)行一次。

          ?????? ??? /**

          ???? * <p>Initialize the servlet mapping under which our controller servlet

          ???? * is being accessed.? This will be used in the <code>&html:form&gt;</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

          ?????? // 這里保存當(dāng)前的servlet名字,保存在actionServletservletName屬性中

          ??????? 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");

          ??????? }

          ?

          ? ??// 取得當(dāng)前的配置文件???

          InputStream input =

          ??????????? getServletContext().getResourceAsStream("/WEB-INF/web.xml");

          ?

          ??????? if (input == null) {

          ??????????? log.error(internal.getMessage("configWebXml"));

          ??????????? throw new ServletException(internal.getMessage("configWebXml"));

          ??????? }

          ?

          ??????? try {

          ???????? ???// 解析當(dāng)前配置文件

          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 {

          ??????????????? // 解析完畢,關(guān)閉輸入

          input.close();

          ??????????? } catch (IOException e) {

          ??????????????? log.error(internal.getMessage("configWebXml"), e);

          ??? /**???????????

          如果有異常,當(dāng)前部進行處理,而是留給他的調(diào)用者來處理。其實是當(dāng)前的調(diào)用部分沒有處理的能力。我們可以這樣理解,假設(shè)你想在出現(xiàn)了這類異常異常的地方給用戶一個提示,但是在我們封裝功能實現(xiàn)的時候,我們并不知道誰會來調(diào)用,所以我們只有把異常拋出,讓調(diào)用者自己去處理。

          ??? 這一點也許不太好理解,不過,如果理解了,可能你就能夠靈活的使用異常了。

          */

          throw new ServletException(e);

          ??????????? }

          ??????? }

          ?

          ??????? // Record a servlet context attribute (if appropriate)

          ??????? if (log.isDebugEnabled()) {

          ??????????? log.debug("Mapping for servlet '" + servletName + "' = '" +

          ??????????????? servletMapping + "'");

          ??????? }

          ?

          ??????? if (servletMapping != null) {

          ??????????? getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping);

          ??????? }

          ?

          ??? }

          [7] 初始化其他模塊

          (1) ? 初始化工廠

          ??????????? getServletContext().setAttribute( Globals . ACTION_SERVLET_KEY , this );

          ??????????? initModuleConfigFactory();

          (2) ? 初始化資源模塊

          ??????????? // Initialize modules as needed

          ??????????? ModuleConfig moduleConfig = initModuleConfig( "" , config );

          ? ?????????? initModuleMessageResources(moduleConfig);

          (3) ? 初始化數(shù)據(jù)源配置模塊

          ??????????? initModuleDataSources(moduleConfig);

          (4) ? 初始化 PlugIn 模塊

          ??????????? initModulePlugIns(moduleConfig);

          ??????????? moduleConfig.freeze();

          [8] ? 初始化參數(shù)

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

          ??????????? }

          [9] ? 我也不知道做什么用的 ???

          ??????????? this .initModulePrefixes( this .getServletContext());

          ???

          ??????????? this .destroyConfigDigester();

          以上就是Struts的初始化流程。

          [10] ???????? 部分模塊的詳細實現(xiàn):

          a. ????? 工廠的初始化如何實現(xiàn)的:

          ??? /**

          ???? * <p>Initialize the factory used to create the module configuration.</p>

          ???? * @since Struts 1.2

          ???? */

          protected void initModuleConfigFactory(){

          /**

          這個部分的代碼就是取得參數(shù)。

          這個參數(shù)你可以自己擴展你的模塊實現(xiàn)工廠。但是一般都沒有自己去做。

          所以一般都使用的默認(rèn)的工廠初始化配置。

          */

          ??????? String configFactory = getServletConfig().getInitParameter("configFactory");

          /**

          下面的代碼,只有你做了自己的配置才會有效。否則一般是不執(zhí)行的。

          */

          ??????? if (configFactory != null) {

          /**

          設(shè)置此工廠,并把其參數(shù)存入到 ModuleConfigFactory.factoryClass 屬性中。

          此部分可以看 ModuleConfigFactory 的代碼。 ModuleConfigFactory 是一個

          */

          ??????????? ModuleConfigFactory.setFactoryClass(configFactory);

          ??????? }

          ??? }

          b. ????? 資源模塊式如何初始化的

          // 調(diào)用的部分

          protected String config = "/WEB-INF/struts-config.xml";

          ------------------------------------------------------------------??????????

          ModuleConfig moduleConfig = initModuleConfig("", config);

          initModuleMessageResources(moduleConfig);

          ?????? // 實現(xiàn)的部分:

          ??? protected void initModuleMessageResources (ModuleConfig config)

          ??????? throws ServletException {

          ?????? ?????? /**

          ?????? struts-config.xml 中的資源文件配置,你可能配置了多個資源,所以此處取得是一個數(shù)組

          */

          ??????? MessageResourcesConfig mrcs[] = config.findMessageResourcesConfigs();

          ?

          ??????? for (int i = 0; i < mrcs.length; i++) {

          ??????????? if ((mrcs[i].getFactory() == null)

          ??????????????? || (mrcs[i].getParameter() == null)) {

          ?????????????? ?continue;

          ??????????? }

          ??????????? if (log.isDebugEnabled()) {

          ??????????????? log.debug(

          ??????????????????? "Initializing module path '"

          ??????????????????????? + config.getPrefix()

          ??????????????????????? + "' message resources from '"

          ?????????????? ?????????+ mrcs[i].getParameter()

          ??????????????????????? + "'");

          ??????????? }

          /**

          ?????? ??? protected String factory =

          ??????? "org.apache.struts.util.PropertyMessageResourcesFactory";

          就是返回的這個值,如果你沒有做其他的設(shè)置的話。

          一般情況下,我們都用得是默認(rèn)的

          */

          ??????????? String factory = mrcs[i].getFactory();

          /**

          ?????? 此處對每一個資源配置文件都回去創(chuàng)建一個工廠

          */

          ??????????? MessageResourcesFactory.setFactoryClass(factory);

          ??????????? MessageResourcesFactory factoryObject =

          ??????????????? MessageResourcesFactory.createFactory();

          ??????????? factoryObject.setConfig(mrcs[i]);

          ??????????? MessageResources resources =

          ??????????????? factoryObject.createResources(mrcs[i].getParameter());

          ??????????? resources.setReturnNull(mrcs[i].getNull());

          ?? ?????????resources.setEscape(mrcs[i].isEscape());

          ?

          ?????? /**

          這一部分非常重要。

          我們之所以能夠直接調(diào)用,就是因為,初始化后,我們就把此 resources 放到了其對應(yīng)的當(dāng)前應(yīng)用的屬性值里面了。之后我們就可以直接調(diào)用了。
          ?????? */

          ??????????? getServletContext().setAttribute(

          ??????????????? mrcs[i].getKey() + config.getPrefix(),

          ??????????????? resources);

          ??????? }

          ?

          ??? }

          c. ????? 數(shù)據(jù)模塊是如何初始化的

          ==========================================================

          // 調(diào)用部分

          initModuleDataSources(moduleConfig);

          ?

          // 實現(xiàn)部分:

          /**

          ???? * <p>Initialize the data sources for the specified module.</p>

          ???? *

          ???? * @param config ModuleConfig information for this module

          ???? *

          ???? * @exception ServletException if initialization cannot be performed

          ???? * @since Struts 1.1

          ???? */

          ??? protected void initModuleDataSources(ModuleConfig config) throws ServletException {

          ?

          ??????? // :FIXME: Document UnavailableException?

          ?

          ??????? if (log.isDebugEnabled()) {

          ??????????? log.debug("Initializing module path '" + config.getPrefix() +

          ??????????????? "' data sources");

          ??????? }

          ?

          ??????? ServletContextWriter scw =

          ??????????? new ServletContextWriter(getServletContext());

          /**

          因為你可能配置了多個數(shù)據(jù)源,所以此處返回的是一個數(shù)組
          */

          ??????? DataSourceConfig dscs[] = config.findDataSourceConfigs();

          ?? ?// 處理沒有配置數(shù)據(jù)源的情況

          if (dscs == null) {

          dscs = new DataSourceConfig[0];

          ??????? }

          /**

          ?????? ??? /**

          ???? * <p>The JDBC data sources that has been configured for this module,

          ???? * if any, keyed by the servlet context attribute under which they are

          ???? * stored.</p>

          ???? */

          protected FastHashMap dataSources = new FastHashMap();

          這是一個加工過的 HashMap ,又不同的工作模式

          ?

          */

          ?

          ??????? dataSources.setFast(false);

          ??????? for (int i = 0; i < dscs.length; i++) {

          ??????????? if (log.isDebugEnabled()) {

          ??????????????? log.debug("Initializing module path '" + config.getPrefix() +

          ??????????????????? "' data source '" + dscs[i].getKey() + "'");

          ??????????? }

          ??????????? DataSource ds = null;

          ??????????? try {

          ?????? ???/**

          */

          ?? ds = (DataSource)

          ??????????????????? RequestUtils.applicationInstance(dscs[i].getType());

          ??????????????? BeanUtils.populate(ds, dscs[i].getProperties());

          ??????????????? ds.setLogWriter(scw);

          ?

          ??????????? } catch (Exception e) {

          ??????????? ????log.error(internal.getMessage("dataSource.init", dscs[i].getKey()), e);

          ??????????????? throw new UnavailableException

          ??????????????????? (internal.getMessage("dataSource.init", dscs[i].getKey()));

          ??????????? }

          /**

          ?????? 這一個部分很重要。

          ?????? 把初始化后的數(shù)據(jù)源放入到 servlet 的屬性中,所以我們才可以通過 struts 的對應(yīng)屬性直接訪問。

          ? protected String key = Globals.DATA_SOURCE_KEY;

          所以,我們可以通過 Globals.DATA_SOURCE_KEY 屬性的值來取得其配制后的數(shù)據(jù)源。

          如果多個的話,可以通過數(shù)據(jù)源的參數(shù) ID 來配置和調(diào)用。

          */

          ??????????? getServletContext().setAttribute

          ??????????????? (dscs[i].getKey() + config.getPrefix(), ds);

          ??????????? dataSources.put(dscs[i].getKey(), ds);

          ??????? }

          ?

          ??????? dataSources.setFast(true);

          ?

          ??? }

          ?

          至此,Struts系統(tǒng)初始化完畢。

          ?

          ?

          ?

          ?

          ?



          |----------------------------------------------------------------------------------------|
                                     版權(quán)聲明  版權(quán)所有 @zhyiwww
                      引用請注明來源 http://www.aygfsteel.com/zhyiwww   
          |----------------------------------------------------------------------------------------|
          posted on 2006-12-25 16:47 zhyiwww 閱讀(3355) 評論(1)  編輯  收藏 所屬分類: j2ee

          FeedBack:
          # re: Struts的資源文件時如何初始化的--struts源碼學(xué)習(xí)
          2007-01-25 13:49 | bearshy
          主站蜘蛛池模板: 普格县| 白河县| 监利县| 石首市| 车险| 梧州市| 兰西县| 梅州市| 砀山县| 阿合奇县| 龙山县| 深泽县| 南通市| 嘉兴市| 开平市| 耒阳市| 霍城县| 昭苏县| 祥云县| 恩平市| 陆良县| 邹城市| 颍上县| 青铜峡市| 彩票| 冷水江市| 西昌市| 如东县| 嘉峪关市| 长沙市| 阜阳市| 舟曲县| 桃源县| 镇坪县| 潍坊市| 田林县| 昭苏县| 密云县| 沽源县| 武平县| 通城县|