This article mainly introduces the detailed explanation of ActionServlet in struts1. The editor thinks it is quite good. Now I will share it with you and give you a reference. Let’s follow the editor and take a look.
In web.xml, in addition to configuring ActionServlet, we also configure some initialization parameter information. First, let’s look at the first config parameter. What is configured here is /WEB-INF/struts -config.xml, because such a configuration information needs to be passed below. The name of this xml file is the standard name of struts1, so the initialization information here can be deleted. If this standard name is not used, it must be configured here. Now we configure the standard name, so we can delete it, why is this? Here you have to look at the ActionServlet source code.
#From the picture we can see that the default config information has been written in ActionServlet, which is the standard name. So it is also possible to delete it here.
Look at the debug and detail parameters below. These two parameter information are related to the settings of the log information level, mainly about parsing the initialization parameters at the configuration file/WEB-INF/struts-config.xml level. These two parameters here can be completely removed without any effect.
Finally there is a load-on-startup configuration, which is the initialization information to initialize the servlet level. If this parameter is greater than or equal to 0, it means that the servlet will be initialized as soon as the server starts, that is, the init method of ActionServlet is called. , this can also be found in the source code of ActionServlet.
When ActionServlet is initialized, it will read the /WEB-INF/struts-config.xml information into the memory. In what form is the memory displayed? We can now take a look at the mvc instance from the previous blog, where the information read in the configuration file is displayed in the form of Actionmapping. In addition, the configuration of servlet-mapping will not be explained. We all know that it matches the url path. When the url-pattern path is encountered, the Actionservlet will be instantiated.
Through this article we know how ActionServlet is instantiated when we request it, and why we need to configure web.xml information. So why do we configure the /WEB-INF/struts-config.xml file? How does ActionServlet pass the request? How does it interact with ActionForm, ActionMapping, Action, etc. to finally complete the user request?
Let’s start with the init method of the ActionServlet source code. Because ActionServlet is a Servlet, it also has the typical methods init, doget, dopost and other methods. Since it is initialization, then we have to look at the init method. The source code of the Init method is as follows:
/** * <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()); } }
Before explaining the process and meaning of this code, it is necessary to say that when we look at the code in eclipse When reading, especially when looking at a long and unfamiliar piece of code, I hope to be able to use the Ctrl key frequently (no unnecessary explanation).
Let’s start with the process of this code and the specific meaning of each step. If there are any errors, I hope to correct them.
The first thing that comes into view is the initInternal() method. The implementation code of this method is:
Code segment one:
/** * <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+ "'"); } }
Code segment two:
/** * 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); }
Code segment three:
/** * 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); } }
The specific function of this method is to initialize MessageResources. The specific implementation is factory mode. First determine whether the defaultFactory exists. If it does not exist, create the factory. defaultFactory = MessageResourcesFactory.createFactory(). Then create the resource class through the factory defaultFactory.createResources(config); if it exists, create the resource class directly.
The initOther() method is mainly to initialize other configurations and obtain the path of our own struts-config configuration file, and its default path is web-inf/struts-config.xml. In addition, this method will also register some conversion classes. The specific source code is:
/** * <p>Initialize other global characteristics ofthe controller servlet</p> * * @exception ServletException if we cannotinitialize these resources */ protectedvoidinitOther() throwsServletException { String value = null; value =getServletConfig().getInitParameter("config"); if (value != null) { config = value; } // Backwards compatibility for form beans of Java wrapper classes // Set to true for strict Struts 0 compatibility value =getServletConfig().getInitParameter("convertNull"); if ("true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value) || "y".equalsIgnoreCase(value) || "1".equalsIgnoreCase(value)) { convertNull = true; } if (convertNull) { ConvertUtils.deregister(); ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class); ConvertUtils.register(new BigIntegerConverter(null), BigInteger.class); ConvertUtils.register(new BooleanConverter(null), Boolean.class); ConvertUtils.register(new ByteConverter(null), Byte.class); ConvertUtils.register(new CharacterConverter(null), Character.class); ConvertUtils.register(new DoubleConverter(null), Double.class); ConvertUtils.register(new FloatConverter(null), Float.class); ConvertUtils.register(new IntegerConverter(null), Integer.class); ConvertUtils.register(new LongConverter(null), Long.class); ConvertUtils.register(new ShortConverter(null), Short.class); } }
The initServlet() method uses digester to read the web.xml file and put it in the servletContext. Specific implementation source code:
/** * <p>Initialize the servlet mapping under which our controller servlet * is being accessed. This will be used in the <code>&html:form></code> * tag to generate correct destination URLs for form submissions.</p> * * @throws ServletException if error happens while scanning web.xml */ protected void initServlet() throws ServletException { // Remember our servlet name this.servletName = getServletConfig().getServletName(); // Prepare a Digester to scan the web application deployment descriptor Digester digester = new Digester(); digester.push(this); digester.setNamespaceAware(true); digester.setValidating(false); // Register our local copy of the DTDs that we can find for (int i = 0; i < registrations.length; i += 2) { URL url = this.getClass().getResource(registrations[i+1]); if (url != null) { digester.register(registrations[i], url.toString()); } } // Configure the processing rules that we need digester.addCallMethod("web-app/servlet-mapping", "addServletMapping", 2); digester.addCallParam("web-app/servlet-mapping/servlet-name", 0); digester.addCallParam("web-app/servlet-mapping/url-pattern", 1); // Process the web application deployment descriptor if (log.isDebugEnabled()) { log.debug("Scanning web.xml for controller servlet mapping"); } InputStream input = getServletContext().getResourceAsStream("/WEB-INF/web.xml"); if (input == null) { log.error(internal.getMessage("configWebXml")); throw new ServletException(internal.getMessage("configWebXml")); } try { digester.parse(input); } catch (IOException e) { log.error(internal.getMessage("configWebXml"), e); throw new ServletException(e); } catch (SAXException e) { log.error(internal.getMessage("configWebXml"), e); throw new ServletException(e); } finally { try { input.close(); } catch (IOException e) { log.error(internal.getMessage("configWebXml"), e); throw new ServletException(e); } } // Record a servlet context attribute (if appropriate) if (log.isDebugEnabled()) { logdebug("Mapping for servlet '" + servletName + "' = '" + servletMapping + "'"); } if (servletMapping != null) { getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping); } }
First of all, before talking about it, let’s write down the specific implementation code of the init method so that everyone can read and understand it easily.
Init source code:
##
public void init() throws ServletException { try { //初始化资源类 initInternal(); //注册转换类 initOther(); //利用digester读取webxml文件并且将其放到servletContext中 initServlet(); getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this); initModuleConfigFactory(); ModuleConfig moduleConfig = initModuleConfig("", config); initModuleMessageResources(moduleConfig); initModuleDataSources(moduleConfig); initModulePlugIns(moduleConfig); moduleConfig.freeze(); Enumeration names = getServletConfig().getInitParameterNames(); while (names.hasMoreElements()) { String name = (String) names.nextElement(); if (!name.startsWith("config/")) { continue; } String prefix = name.substring(6); moduleConfig = initModuleConfig (prefix, getServletConfig()getInitParameter(name)); initModuleMessageResources(moduleConfig); initModuleDataSources(moduleConfig); initModulePlugIns(moduleConfig); moduleConfig.freeze(); } this.initModulePrefixes(this.getServletContext()); this.destroyConfigDigester(); } catch (UnavailableException ex) { throw ex; } catch (Throwable t) { log.error("Unable to initialize Struts ActionServlet due to an " + "unexpected exception or error thrown, so marking the " + "servlet as unavailable Most likely, this is due to an " + "incorrect or missing library dependency", t); throw new UnavailableException(t.getMessage()); } }
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完成。
The above is the detailed content of Detailed explanation of examples of ActionServlet in struts1. For more information, please follow other related articles on the PHP Chinese website!