Maison > Java > javaDidacticiel > Explication détaillée des exemples d'ActionServlet dans struts1

Explication détaillée des exemples d'ActionServlet dans struts1

黄舟
Libérer: 2017-09-05 11:31:20
original
1505 Les gens l'ont consulté

Cet article présente principalement l'explication détaillée d'ActionServlet dans struts1. L'éditeur pense que c'est assez bon, je vais le partager avec vous maintenant et le donner comme référence. Suivons l'éditeur et jetons un coup d'œil.

Dans web.xml, en plus de configurer ActionServlet, nous configurons également certaines informations sur les paramètres d'initialisation. Tout d'abord, regardons le premier paramètre de configuration. Ce qui est configuré ici est /. WEB-INF/struts -config.xml, car ces informations de configuration doivent être transmises ci-dessous. Le nom de ce fichier XML est le nom standard de struts1, donc les informations d'initialisation ici peuvent être supprimées si ce nom standard n'est pas utilisé. , il doit être configuré ici. Maintenant, nous configurons le nom standard, afin de pouvoir le supprimer, pourquoi ? Ici, vous devez regarder le code source d'ActionServlet.

Sur l'image, nous pouvons voir que les informations de configuration par défaut ont été écrites dans ActionServlet, qui est le nom standard. Il est donc également possible de le supprimer ici.
Regardez les paramètres de débogage et de détail ci-dessous. Ces deux informations sur les paramètres sont liées aux paramètres du niveau d'informations du journal, principalement sur l'analyse des paramètres d'initialisation au niveau du fichier de configuration/WEB-INF/struts-config.xml. Ces deux paramètres peuvent ici être complètement supprimés sans aucun effet.

Enfin il y a une configuration de chargement au démarrage, qui est l'information d'initialisation pour initialiser le niveau du servlet. Si ce paramètre est supérieur ou égal à 0, cela signifie que le servlet est initialisé dès que le niveau du servlet est initialisé. Le serveur démarre, c'est-à-dire que la méthode init d'ActionServlet est appelée, cela peut également être trouvé dans le code source d'ActionServlet.

Lorsque ActionServlet est initialisé, il lira les informations /WEB-INF/struts-config.xml dans la mémoire. Sous quelle forme la mémoire est-elle affichée ? On peut maintenant jeter un oeil à l'instance mvc du blog précédent, où les informations lues dans le fichier de configuration sont affichées sous forme d'Actionmapping. De plus, la configuration du mappage de servlet ne sera pas expliquée. Nous savons tous qu'il correspond au chemin de l'url. Lorsque le chemin du modèle d'url est rencontré, l'Actionservlet sera instanciée.

Grâce à cet article, nous savons comment ActionServlet est instancié lorsque nous le demandons, et pourquoi nous devons configurer les informations web.xml. Alors pourquoi configurons-nous le fichier /WEB-INF/struts-config.xml ? Comment ActionServlet transmet-il la requête ? Comment interagit-il avec ActionForm, ActionMapping, Action, etc. pour finalement compléter la requête de l'utilisateur ?

Commençons par la méthode init du code source d'ActionServlet. Parce qu'ActionServlet est un servlet, il possède également les méthodes typiques init, doget, dopost et d'autres méthodes. Puisqu’il s’agit d’une initialisation, nous devons alors examiner la méthode init. Le code source de la méthode Init est le suivant :


/** 
   * <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()); 
    }   
}
Copier après la connexion

Avant d'expliquer le processus et la signification de ce code, il faut dire que lorsque l'on êtes dans Eclipse Lors de la lecture de code, en particulier lorsque vous regardez un morceau de code long et inconnu, j'espère pouvoir utiliser fréquemment la touche Ctrl (pas d'explication inutile).

Ce qui suit expliquera le processus de ce code et la signification spécifique de chaque étape. S'il y a quelque chose d'incorrect, j'espère le corriger.

La première chose qui apparaît est la méthode initInternal(). Le code d'implémentation de cette méthode est :

Segment de code un :


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

Segment de code deux :


/** 
   * 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); 
}
Copier après la connexion

Segment de code trois :


/** 
   * 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); 
    } 
  
}
Copier après la connexion

La fonction spécifique de cette méthode est de initialiser MessageResources.L'implémentation spécifique est le mode usine.Déterminez d'abord si defaultFactory existe. S'il n'existe pas, créez l'usine defaultFactory = MessageResourcesFactory.createFactory(). ; si elle existe, créez directement la classe de ressources.

La méthode initOther() sert principalement à initialiser d'autres configurations et à obtenir le chemin de notre propre fichier de configuration struts-config, et son chemin par défaut est web-inf/struts-config.xml. , cette méthode enregistrera également certaines classes de conversion. Le code source spécifique est :


/** 
   * <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); 
    } 
  
}
Copier après la connexion

La méthode initServlet() utilise digester pour lire le fichier web.xml et le placer dans le servletContext. Code source d'implémentation spécifique :


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

Tout d'abord, avant d'en parler, permettez-moi de parler du code d'implémentation spécifique de la méthode init et de l'écrire afin que tout le monde puisse le lire et le comprendre facilement.

Code source d'initialisation :


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()); 
 }   
}
Copier après la connexion

getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY,this); L'instance sera stockée dans le contexte de servlet avec Globals.ACTION_SERVLET_KEY comme clé.

Le Globals.ACTION_SERVLET_KEY ici a été déclaré dans ActionServlet :


public static final String ACTION_SERVLET_KEY= "org.apache.struts.action.ACTION_SERVLET";
Copier après la connexion

接下来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); 
    } 
}
Copier après la connexion

代码段二:


public static void setFactoryClass(String factoryClass) { 
    ModuleConfigFactory.factoryClass = factoryClass; 
    ModuleConfigFactory.clazz = null; 
  }
Copier après la connexion

代码段三:


protected static String factoryClass = 
    "org.apache.struts.config.impl.DefaultModuleConfigFactory"; 
}
Copier après la connexion

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

具体实现代码:


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

这里有必要解析一下这段代码。首先得到继承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完成。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal