深入浅出学习Struts1框架(七):ActionServlet实例化之读取struts-config.xml配置文件

来源:互联网 发布:培训课程网络促销方案 编辑:程序博客网 时间:2024/05/29 09:33

在上一篇博客中讲到ActionServlet是如何初始化的以及web.xml的配置信息的具体作用。今天我们讲继续讲解ActionServlet在初始化的时候如何读取/WEB-INF/struts-config.xml信息到内存中,如何将这些从配置文件读取的信息以Actionmapping的形式展现在内存中的。

 

由于这部分内容是比较繁琐的,所以我对这部分的深入分析也不能太详细,但是具体实现流程我会讲清晰,如果有兴趣研究的童鞋们希望能够继续深入,研究的非常透彻的时候,可以给我发邮件或Q我。

 

下面来开始今天的博客,我们先从ActionServlet源代码的init方法开始。因为ActionServlet就是一个Servlet,它也是具有典型的那几个方法init、doget、dopost等方法。既然是初始化,那么我们就要看init方法。Init方法的源代码如下:

   

[java] view plaincopyprint?
  1. /** 
  2.      * <p>Initialize this servlet.  Most of the processing has been factored into 
  3.      * support methods so that you can overrideparticular functionality at a 
  4.      * fairly granular level.</p> 
  5.      * 
  6.      * @exception ServletException if we cannotconfigure ourselves correctly 
  7.      */  
  8.    publicvoidinit() throwsServletException {  
  9.    
  10.         // Wraps the entire initialization in a try/catch tobetter handle  
  11.         // unexpected exceptions and errors to provide better feedback  
  12.         // to the developer  
  13.         try {  
  14.             initInternal();  
  15.             initOther();  
  16.             initServlet();  
  17.      
  18.            getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);  
  19.             initModuleConfigFactory();  
  20.             // Initialize modules as needed  
  21.             ModuleConfig moduleConfig =initModuleConfig("", config);  
  22.            initModuleMessageResources(moduleConfig);  
  23.            initModuleDataSources(moduleConfig);  
  24.             initModulePlugIns(moduleConfig);  
  25.             moduleConfig.freeze();  
  26.      
  27.             Enumeration names =getServletConfig().getInitParameterNames();  
  28.             while (names.hasMoreElements()) {  
  29.                 String name = (String)names.nextElement();  
  30.                 if (!name.startsWith("config/")) {  
  31.                     continue;  
  32.                 }  
  33.                 String prefix =name.substring(6);  
  34.                 moduleConfig = initModuleConfig  
  35.                     (prefix,getServletConfig().getInitParameter(name));  
  36.                initModuleMessageResources(moduleConfig);  
  37.                 initModuleDataSources(moduleConfig);  
  38.                initModulePlugIns(moduleConfig);  
  39.                 moduleConfig.freeze();  
  40.             }  
  41.      
  42.             this.initModulePrefixes(this.getServletContext());  
  43.      
  44.             this.destroyConfigDigester();  
  45.         } catch (UnavailableException ex) {  
  46.             throw ex;  
  47.         } catch (Throwable t) {  
  48.    
  49.             // The follow error message is not retrieved from internal message  
  50.             // resources as they may not have been able to have been  
  51.             // initialized  
  52.             log.error("Unable to initialize Struts ActionServlet due to an "  
  53.                 + "unexpected exception or error thrown, so marking the "  
  54.                 + "servlet as unavailable.  Mostlikely, this is due to an "  
  55.                 + "incorrect or missing library dependency.", t);  
  56.             throw new UnavailableException(t.getMessage());  
  57.         }     
  58. }  

 

在解释这段代码的流程和意思之前,有必要说一句,就是当我们在eclipse里面看代码的时候,尤其是看一段生疏的很长的代码的时候,希望能够经常使用Ctrl键(多余的不解释)。

 

下面开始讲解这段代码的流程和具体每一步的含义,如果有不正确的地方,希望指正。

首先映入眼帘的是initInternal()方法。这个方法的实现代码是:

代码段一:

[java] view plaincopyprint?
  1. /** 
  2.      * <p>Initialize our internal MessageResourcesbundle.</p> 
  3.      * 
  4.      * @exception ServletException if we cannotinitialize these resources 
  5.      */  
  6.    protectedvoidinitInternal() throwsServletException {  
  7.    
  8.         // :FIXME: Document UnavailableException  
  9.    
  10.         try {  
  11.             internal = MessageResources.getMessageResources(internalName);  
  12.         } catch (MissingResourceException e) {  
  13.             log.error("Cannot load internal resources from '"+ internalName+ "'",  
  14.                 e);  
  15.             throw new UnavailableException  
  16.                 ("Cannot load internal resources from '"+ internalName+ "'");  
  17.         }  
  18.    
  19. }  


 

代码段二:

[java] view plaincopyprint?
  1. /** 
  2.      * Create and return an instance of <code>MessageResources</code> for the 
  3.      * created by the default <code>MessageResourcesFactory</code>. 
  4.      * 
  5.      * @param config Configuration parameterfor this message bundle. 
  6.      */  
  7.    publicsynchronizedstaticMessageResources getMessageResources(String config) {  
  8.    
  9.         if (defaultFactory == null) {  
  10.             defaultFactory =MessageResourcesFactory.createFactory();  
  11.         }  
  12.    
  13.         return defaultFactory.createResources(config);  
  14. }  


代码段三:

[java] view plaincopyprint?
  1. /** 
  2.      * Create and return a <code>MessageResourcesFactory</code> instance ofthe 
  3.      * appropriate class, which can be used tocreate customized 
  4.      * <code>MessageResources</code>instances.  If no such factory can be 
  5.      * created, return <code>null</code> instead. 
  6.      */  
  7.    publicstaticMessageResourcesFactory createFactory(){  
  8.    
  9.         // Construct a new instance of the specified factory class  
  10.         try {  
  11.             if (clazz == null)  
  12.                 clazz = RequestUtils.applicationClass(factoryClass);  
  13.             MessageResourcesFactory factory =  
  14.                 (MessageResourcesFactory) clazz.newInstance();  
  15.             return (factory);  
  16.         } catch (Throwable t) {  
  17.             LOG.error("MessageResourcesFactory.createFactory",t);  
  18.             return (null);  
  19.         }  
  20.    
  21. }  


这个方法的具体作用就是初始化MessageResources,具体实现是工厂模式,首先判断defaultFactory是否存在,不存在则创建工厂,

defaultFactory = MessageResourcesFactory.createFactory(),在通过工厂创建资源类defaultFactory.createResources(config);存在则直接创建资源类。

initOther()的方法,主要是初始化其它的配置,获取我们自己的struts-config配置文件的路径,
而它的默认路径就是web-inf/struts-config.xml,另外这个方法还会注册一些转换类的。具体源代码是:

[java] view plaincopyprint?
  1. /** 
  2.      * <p>Initialize other global characteristics ofthe controller servlet.</p> 
  3.      * 
  4.      * @exception ServletException if we cannotinitialize these resources 
  5.      */  
  6.    protectedvoidinitOther() throwsServletException {  
  7.    
  8.         String value = null;  
  9.         value =getServletConfig().getInitParameter("config");  
  10.         if (value != null) {  
  11.             config = value;  
  12.         }  
  13.    
  14.         // Backwards compatibility for form beans of Java wrapper classes  
  15.         // Set to true for strict Struts 1.0 compatibility  
  16.         value =getServletConfig().getInitParameter("convertNull");  
  17.         if ("true".equalsIgnoreCase(value)  
  18.             || "yes".equalsIgnoreCase(value)  
  19.             || "on".equalsIgnoreCase(value)  
  20.            || "y".equalsIgnoreCase(value)  
  21.             || "1".equalsIgnoreCase(value)) {  
  22.    
  23.             convertNull = true;  
  24.         }  
  25.    
  26.         if (convertNull) {  
  27.             ConvertUtils.deregister();  
  28.             ConvertUtils.register(new BigDecimalConverter(null), BigDecimal.class);  
  29.             ConvertUtils.register(new BigIntegerConverter(null), BigInteger.class);  
  30.             ConvertUtils.register(new BooleanConverter(null), Boolean.class);  
  31.             ConvertUtils.register(new ByteConverter(null), Byte.class);  
  32.             ConvertUtils.register(new CharacterConverter(null), Character.class);  
  33.             ConvertUtils.register(new DoubleConverter(null), Double.class);  
  34.             ConvertUtils.register(new FloatConverter(null), Float.class);  
  35.             ConvertUtils.register(new IntegerConverter(null), Integer.class);  
  36.             ConvertUtils.register(new LongConverter(null), Long.class);  
  37.             ConvertUtils.register(new ShortConverter(null), Short.class);  
  38.         }  
  39.    
  40. }  


initServlet()方法是利用digester读取web.xml文件并且放到servletContext中。具体实现源代码:

[java] view plaincopyprint?
  1. /** 
  2.  * <p>Initialize the servlet mapping under which our controller servlet 
  3.  * is being accessed.  This will be used in the <code>&html:form></code> 
  4.  * tag to generate correct destination URLs for form submissions.</p> 
  5.  * 
  6.  * @throws ServletException if error happens while scanning web.xml 
  7.  */  
  8. protected void initServlet() throws ServletException {  
  9.   
  10.     // Remember our servlet name  
  11.     this.servletName = getServletConfig().getServletName();  
  12.   
  13.     // Prepare a Digester to scan the web application deployment descriptor  
  14.     Digester digester = new Digester();  
  15.     digester.push(this);  
  16.     digester.setNamespaceAware(true);  
  17.     digester.setValidating(false);  
  18.   
  19.     // Register our local copy of the DTDs that we can find  
  20.     for (int i = 0; i < registrations.length; i += 2) {  
  21.         URL url = this.getClass().getResource(registrations[i+1]);  
  22.         if (url != null) {  
  23.             digester.register(registrations[i], url.toString());  
  24.         }  
  25.     }  
  26.   
  27.     // Configure the processing rules that we need  
  28.     digester.addCallMethod("web-app/servlet-mapping",  
  29.                            "addServletMapping"2);  
  30.     digester.addCallParam("web-app/servlet-mapping/servlet-name"0);  
  31.     digester.addCallParam("web-app/servlet-mapping/url-pattern"1);  
  32.   
  33.     // Process the web application deployment descriptor  
  34.     if (log.isDebugEnabled()) {  
  35.         log.debug("Scanning web.xml for controller servlet mapping");  
  36.     }  
  37.   
  38.     InputStream input =  
  39.         getServletContext().getResourceAsStream("/WEB-INF/web.xml");  
  40.   
  41.     if (input == null) {  
  42.         log.error(internal.getMessage("configWebXml"));  
  43.         throw new ServletException(internal.getMessage("configWebXml"));  
  44.     }  
  45.   
  46.     try {  
  47.         digester.parse(input);  
  48.   
  49.     } catch (IOException e) {  
  50.         log.error(internal.getMessage("configWebXml"), e);  
  51.         throw new ServletException(e);  
  52.   
  53.     } catch (SAXException e) {  
  54.         log.error(internal.getMessage("configWebXml"), e);  
  55.         throw new ServletException(e);  
  56.   
  57.     } finally {  
  58.         try {  
  59.             input.close();  
  60.         } catch (IOException e) {  
  61.             log.error(internal.getMessage("configWebXml"), e);  
  62.             throw new ServletException(e);  
  63.         }  
  64.     }  
  65.   
  66.     // Record a servlet context attribute (if appropriate)  
  67.     if (log.isDebugEnabled()) {  
  68.         log.debug("Mapping for servlet '" + servletName + "' = '" +  
  69.             servletMapping + "'");  
  70.     }  
  71.   
  72.     if (servletMapping != null) {  
  73.         getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping);  
  74.     }  
  75.   
  76. }  


 

这篇博客先介绍这几个方法,随着这些方法具体作用和具体实现的慢慢的我们就知道init方法的作用,也慢慢的就解开了当我们实例化ActionServlet的时候,digester是如何读取/WEB-INF/struts-config.xml的文件内容,并且放到了ActionMapping中。敬请期待!

0 0
原创粉丝点击