この記事では主に struts1 の ActionServlet の詳細な説明を紹介します。これが非常に優れていると思いますので、参考にしてください。エディターに従って見てみましょう
web.xml では、ActionServlet の構成に加えて、いくつかの初期化パラメーター情報も構成します。まず、ここで構成されているのは /WEB-INF/struts です。 -config.xml 。このような構成情報は以下に渡す必要があるため、この XML ファイルの名前は struts1 の標準名であるため、この標準名が使用されない場合は、この初期化情報を完全に削除する必要があります。ここで設定されます。ここで標準名を設定したので、削除できるようになりました。これはなぜでしょうか?ここで、ActionServlet のソース コードを確認する必要があります。
写真を見ると、標準名であるActionServletにデフォルトの設定情報が書き込まれていることが分かります。したがって、ここで削除することも可能です。
以下のデバッグパラメータと詳細パラメータを見てください。これらの 2 つのパラメータ情報は、主に構成ファイル/WEB-INF/struts-config.xml レベルでの初期化パラメータの解析に関するログ情報レベルの設定に関連しています。ここでのこれら 2 つのパラメーターは、何の影響もなく完全に削除できます。
最後に、load-on-startup 構成があります。これは、サーブレット レベルを初期化するための初期化情報です。このパラメーターが 0 以上の場合、サーバーが起動するとすぐにサーブレットが初期化されることを意味します。つまり、ActionServlet の init メソッドが呼び出されます。これは、ActionServlet のソース コードに移動して見つけることもできます。
ActionServlet が初期化されると、/WEB-INF/struts-config.xml 情報がメモリに読み込まれ、メモリはどのような形式で表示されますか?前回のブログの mvc インスタンスを見てみましょう。構成ファイルに読み取られた情報がアクションマッピングの形式で表示されます。さらに、サーブレット マッピングの構成については説明しませんが、URL パターン パスに一致すると、Actionservlet がインスタンス化されることがわかります。
この記事を通じて、ActionServlet がリクエストされたときにどのようにインスタンス化されるか、そしてなぜ web.xml 情報を設定する必要があるのかを理解しました。では、なぜ /WEB-INF/struts-config.xml ファイルを設定するのでしょうか? ActionServlet はどのようにリクエストを転送するのでしょうか? 最終的にユーザーのリクエストを完了するために、ActionForm、ActionMapping、Action などとどのようにやり取りするのでしょうか?
ActionServlet ソース コードの init メソッドから始めましょう。 ActionServlet はサーブレットであるため、init、doget、dopost などの代表的なメソッドも備えています。これは初期化なので、init メソッドを確認する必要があります。 Init メソッドのソース コードは次のとおりです。
/** * <p>Initialize this servlet. Most of the processing has been factored into * support methods so that you can overrideparticular functionality at a * fairly granular level.</p> * * @exception ServletException if we cannotconfigure ourselves correctly */ publicvoidinit() throwsServletException { // Wraps the entire initialization in a try/catch tobetter handle // unexpected exceptions and errors to provide better feedback // to the developer try { initInternal(); initOther(); initServlet(); getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this); initModuleConfigFactory(); // Initialize modules as needed ModuleConfig moduleConfig =initModuleConfig("", config); initModuleMessageResources(moduleConfig); initModuleDataSources(moduleConfig); initModulePlugIns(moduleConfig); moduleConfig.freeze(); Enumeration names =getServletConfig().getInitParameterNames(); while (names.hasMoreElements()) { String name = (String)namesnextElement(); if (!name.startsWith("config/")) { continue; } String prefix =name.substring(6); moduleConfig = initModuleConfig (prefix,getServletConfig().getInitParameter(name)); initModuleMessageResources(moduleConfig); initModuleDataSources(moduleConfig); initModulePlugIns(moduleConfig); moduleConfig.freeze(); } this.initModulePrefixes(this.getServletContext()); thisdestroyConfigDigester(); } catch (UnavailableException ex) { throw ex; } catch (Throwable t) { // The follow error message is not retrieved from internal message // resources as they may not have been able to have been // initialized logerror("Unable to initialize Struts ActionServlet due to an " + "unexpected exception or error thrown, so marking the " + "servlet as unavailable. Mostlikely, this is due to an " + "incorrect or missing library dependency.", t); throw new UnavailableException(t.getMessage()); } }
このコードのプロセスと意味を説明する前に、Eclipse のコードを見るとき、特に長くて見慣れない段落 コーディングの際、Ctrlキーを頻繁に使えるようになりたいです(余計な説明は無し)。
このコードのプロセスと各ステップの具体的な意味を説明していきます。間違いがある場合は修正したいと思います。
最初に目に入るのは initInternal() メソッドです。このメソッドの実装コードは次のとおりです。codeセグメント1:
codeセグメント2:
codeセグメント3:
/** * <p>Initialize our internal MessageResourcesbundle</p> * * @exception ServletException if we cannotinitialize these resources */ protectedvoidinitInternal() throwsServletException { // :FIXME: Document UnavailableException try { internal = MessageResourcesgetMessageResources(internalName); } catch (MissingResourceException e) { log.error("Cannot load internal resources from '"+ internalName+ "'", e); throw new UnavailableException ("Cannot load internal resources from '"+ internalName+ "'"); } }
/** * Create and return an instance of <code>MessageResources</code> for the * created by the default <code>MessageResourcesFactory</code>. * * @param config Configuration parameterfor this message bundle. */ publicsynchronizedstaticMessageResources getMessageResources(String config) { if (defaultFactory == null) { defaultFactory =MessageResourcesFactory.createFactory(); } return defaultFactory.createResources(config); }
Init ソース コード:
/** * Create and return a <code>MessageResourcesFactory</code> instance ofthe * appropriate class, which can be used tocreate customized * <code>MessageResources</code>instances If no such factory can be * created, return <code>null</code> instead */ publicstaticMessageResourcesFactory createFactory(){ // Construct a new instance of the specified factory class try { if (clazz == null) clazz = RequestUtils.applicationClass(factoryClass); MessageResourcesFactory factory = (MessageResourcesFactory) clazz.newInstance(); return (factory); } catch (Throwable t) { LOG.error("MessageResourcesFactory.createFactory",t); return (null); } }
ここの Globals.ACTION_SERVLET_KEY は ActionServlet で宣言されています:
public static final String ACTION_SERVLET_KEY= "org.apache.struts.action.ACTION_SERVLET";
接下来initModuleConfigFactory()方法,这个方法主要的作用是解析在web.xml中configFactory的text值。如果configFactory有配置,则将设置ModuleConfigFactory中得factoryClass值,否则默认得为efaultModuleConfigFactory。该方法其实宗旨是让开发人员自己开发出ModuleConfigFactory,从而得到自己所需要的ModuleConfig类。因为我们的实例中没有配置这个参数信息,所以我们这里的实例是要defalutModelConfigFactory了。
代码段一:
protected voidinitModuleConfigFactory(){ String configFactory =getServletConfig().getInitParameter("configFactory"); if (configFactory != null) { ModuleConfigFactory.setFactoryClass(configFactory); } }
代码段二:
public static void setFactoryClass(String factoryClass) { ModuleConfigFactory.factoryClass = factoryClass; ModuleConfigFactory.clazz = null; }
代码段三:
protected static String factoryClass = "org.apache.struts.config.impl.DefaultModuleConfigFactory"; }
ModuleConfig moduleConfig =initModuleConfig("", config)方法是非常重要的,initModuleConfig方法给strits-config里面的属性初始化后放入moduleConfig对象里面去,放到moduleConfig对象里面去便于以后操作更快,因为它是文件流。
具体实现代码:
protected ModuleConfig initModuleConfig(Stringprefix, String paths) throws ServletException { // :FIXME: Document UnavailableException? (Doesn't actually throw anything) if (log.isDebugEnabled()) { log.debug( "Initializing module path '" + prefix + "' configuration from '" + paths + "'"); } // Parse the configuration for this module ModuleConfigFactory factoryObject= ModuleConfigFactory.createFactory(); ModuleConfig config =factoryObject.createModuleConfig(prefix); // Configure the Digester instance we will use Digester digester =initConfigDigester(); // Process each specified resource path while (paths.length() > 0) { digester.push(config); String path = null; int comma = paths.indexOf(','); if (comma >= 0) { path =paths.substring(0, comma).trim(); paths =paths.substring(comma + 1); } else { path = pathstrim(); paths = ""; } if (pathlength() < 1){ break; } this.parseModuleConfigFile(digester,path); } getServletContext().setAttribute( Globals.MODULE_KEY +config.getPrefix(), config); // Force creation and registration of DynaActionFormClass instances // for all dynamic form beans we wil be using FormBeanConfig fbs[] =config.findFormBeanConfigs(); for (int i = 0; i < fbs.length; i++) { if (fbs[i].getDynamic()) { fbs[i].getDynaActionFormClass(); } } return config; }
这里有必要解析一下这段代码。首先得到继承ModuleConfigFactory的实现类,如果在initModuleConfigFactory()中能设置factoryClass属性,则能生成客户化得factory,否则得到得是默认得DefaultModuleConfigFactory类,该工厂得到ModuleConfigImpl类。然后调用initConfigDigester()该方法为解析配置文件做准备,初始化Digest类(具体digest的初始化实现就不讲解)。最后返回ModuleConfig,而这时的ModuleConfig里面封装了所有的struts-config.xml中的信息。
最后的几个方法就简单说一下就行,不是非常难理解:
initModuleMessageResources(moduleConfig)方法是通过moduleConfig中的配置文件信息,创建MessageResource对象.
initModuleDataSources(moduleConfig)方法是通过moduleConfig中的配置文件信息,创建DataSource对象. initModulePlugIns(moduleConfig)加载并初始化默认应用模块的所有插件的。
moduleConfig.freeze()是将配置文件中的各个对象,设置成已配置状态.
最后我们看到了,下面还有一段同上面代码的循环代码,这段代码的主要意思就是当默认子应用模块被成功初始化后,如果应用还包括其他子应用模块,将重复流程,分别对其他子应用模块进行初始化。这个也是很好理解的。
到此为止ActionServlet就init完成。
以上がstruts1 の ActionServlet コード共有の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。