`
bolan392
  • 浏览: 273958 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Struts1.3.x中ActionServlet源码分析之初始化

阅读更多
  1. ActionServlet中的常量定义

    //公共的日志实例

    protected static Log log = LogFactory.getLog(ActionServlet.class);

    //默认的配置文件路径
    protected String config = "/WEB-INF/struts-config.xml";

    //默认的处理流程配置文件  

    protected String chainConfig = "org/apache/struts/chain/chain-config.xml";

    //未知   

    protected Digester configDigester = null;

    //convertNull若为true,则struts中Java包装类的初始值为null

    protected boolean convertNull = false;

    //未知    

    protected MessageResources internal = null;

    //默认的资源文件    

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

    //用来验证配置文件格式的dtd文件    

    protected String[] registrations =
        {
            "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
            "/org/apache/struts/resources/struts-config_1_0.dtd",
            "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN",
            "/org/apache/struts/resources/struts-config_1_1.dtd",
            "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN",
            "/org/apache/struts/resources/struts-config_1_2.dtd",
            "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN",
            "/org/apache/struts/resources/struts-config_1_3.dtd",
            "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",
            "/org/apache/struts/resources/web-app_2_3.dtd"
        };

     //未知   

     protected String servletMapping = null; // :FIXME: - multiples?

     //未知
     protected String servletName = null;

 

2.  ActionServlet中init方法的执行流程

 

     public void init() throws ServletException {
        final String configPrefix = "config/";
        final int configPrefixLength = configPrefix.length() - 1;

       
        try {

            //①内部资源文件的初始化

            initInternal();

            //②从web.xml文件中加载ActionServlet的初始化参数:config\convetrNull
            initOther();

            //③从web.xml文件中加载ActionServlet的初始化参数:servlet-name,加载DTD文件并把其放入HashMap缓存,读取并解析web.xml的内容
            initServlet();

            //④读取web.xml中命令链文件初始值chainConfig 
            initChain();

            //把servlet对象存储到servletContext中,属性名为Globals.ACTION_SERVLET_KEY

            getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
            //⑤调用 initModuleConfigFactory(); 和 initModuleConfig("", config); 创建ModuleConfig 对象。Struts中的MessageResource、PlugIn、数据源等,都是通过ModuleConfig来实现的

            initModuleConfigFactory();

            // Initialize modules as needed
            ModuleConfig moduleConfig = initModuleConfig("", config);

            //⑥用户资源文件的初始化 initModuleMessageResources(moduleConfig);

            initModuleMessageResources(moduleConfig);

            //⑦用户插件的初始化 initModulePlugIns(moduleConfig); 
            initModulePlugIns(moduleConfig);         

       //⑧ 把struts配置文件中的其他配置存储到servletContext中,包括 
            initModuleFormBeans(moduleConfig);
            initModuleForwards(moduleConfig);
            initModuleExceptionConfigs(moduleConfig);
            initModuleActions(moduleConfig);           

          //⑨ 调用moduleConfig.freeze();

             /* 使ModuleConfig中的 actionConfigs/actionConfigList exceptions formBeansforwardsmessageResourcesplugIns等的配置等变得不可改变 */ 
                   moduleConfig.freeze();

 

                

⑩ 解析以"config/"开头的其他struts配置文件

// 遍历web.xml中servletConfig配置的 initParameterNames

// 如发现以" config/ " 开始的parameter,则根据此值初始化其它的ModuleConfig

            Enumeration names = getServletConfig().getInitParameterNames();

            while (names.hasMoreElements()) {
                String name = (String) names.nextElement();

                if (!name.startsWith(configPrefix)) {
                    continue;
                }

                String prefix = name.substring(configPrefixLength);

                moduleConfig =
                    initModuleConfig(prefix,
                        getServletConfig().getInitParameter(name));
                initModuleMessageResources(moduleConfig);
                initModulePlugIns(moduleConfig);
                initModuleFormBeans(moduleConfig);
                initModuleForwards(moduleConfig);
                initModuleExceptionConfigs(moduleConfig);
                initModuleActions(moduleConfig);
                moduleConfig.freeze();
            }

            // 初始化其他模块的前缀

        

/* 把其他模块prefixes存储到servletContext中,属性名为

Globals.MODULE_PREFIXES_KEY " org.apache.struts.globals.MODULE_PREFIXES " */

 

 

            this.initModulePrefixes(this.getServletContext());

          // 设置configDigester = null,释放内存

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

 

 

  3.ActionServlet中init()方法调用的各个方法详解

  

  ①内部资源文件的初始化 initInternal()方法;

    

// initInternal 方法中通过下面得到一个MessageResources对象

internal = MessageResources.getMessageResources(internalName);

此资源文件主要包括一些消息信息的定义,具体可参考org.apache.struts.action下的ActionResources.properties文件

 

 

  ②从web.xml文件中加载ActionServlet的初始化参数:config\convetrNull initOther();

 

    protected void initOther()
        throws ServletException {
        String value;

        //得到web.xml文件中的"config"参数

        value = getServletConfig().getInitParameter("config");

        if (value != null) {
            config = value;
        }

        //获得web.xml文件中convertNull的值,如果此参数的值为true,则所有数值型类型(Integer,Double)的Java

           包装类的初始值为null,而非0

        value = getServletConfig().getInitParameter("convertNull");

        if ("true".equalsIgnoreCase(value) || "yes".equalsIgnoreCase(value)
            || "on".equalsIgnoreCase(value) || "y".equalsIgnoreCase(value)
            || "1".equalsIgnoreCase(value)) {
            convertNull = true;
        }

        if (convertNull) {

            //将所有的转换器注销掉,使所有值初始为null
            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);
        }
    }

 

    ③initServlet();从web.xml文件中加载ActionServlet的初始化参数:servlet-name,加载DTD文件并把其放入HashMap缓存,读取并解析   

     web.xml的内容

     

     protected void initServlet()
        throws ServletException {
        //获取当前Servlet的名称,即web.xml文件中定义的<servlet-name>
        this.servletName = getServletConfig().getServletName();

        Digester digester = new Digester();

        // 把当前的 ActionServlet 对象放入到解析堆栈中

        digester.push(this);
        //需要考虑命名空间

        digester.setNamespaceAware(true);

        // 缺省值[false] ,解析器只是检查XML是否格式良好(well formed) 
        digester.setValidating(false);

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

        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()) {
            log.debug("Mapping for servlet '" + servletName + "' = '"
                + servletMapping + "'");
        }

        if (servletMapping != null) {
            getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping);
        }
    }

    

     

      读取web.xml中命令链文件初始值chainConfig initChain();

         

         protected void initChain()
        throws ServletException {
        // Parse the configuration file specified by path or resource
        try {
            String value;

            //读取web.xml文件中的chainConfig参数值,如没有chainConfig参数,则使用默认 "org/apache/struts/chain/chain-config.xml"

            value = getServletConfig().getInitParameter("chainConfig");

            if (value != null) {
                chainConfig = value;
            }

            ConfigParser parser = new ConfigParser();
            List urls = splitAndResolvePaths(chainConfig);
            URL resource;

            for (Iterator i = urls.iterator(); i.hasNext();) {
                resource = (URL) i.next();
                log.info("Loading chain catalog from " + resource);

                // chainConfig 替换了原来传统的在 RequestProcessor 类中执行的 HTTP 请求处理
                parser.parse(resource);
            }
        } catch (Exception e) {
            log.error("Exception loading resources", e);
            throw new ServletException(e);
        }
    }

 

   

    ⑤调用 initModuleConfigFactory(); 和 initModuleConfig("", config); 创建ModuleConfig 对象。Struts中的MessageResource、

     PlugIn、数据源等,都是通过ModuleConfig来实现的

    

        protected void initModuleConfigFactory() {
        // 得到web.xml中"configFactory"参数,如果找不到,则使用 默认工厂

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

        if (configFactory != null) {
            ModuleConfigFactory.setFactoryClass(configFactory);
        }
        }

 

        protected ModuleConfig initModuleConfig(String prefix, String paths)
        throws ServletException {
        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();

        /* 循环struts配置文件(用","分开的多个struts配置文件)并解析, parseModuleConfigFile 执行之后可以 从struts-config.xml等配置文件中得到 actionConfigs/actionConfigList exceptions formBeansforwardsmessageResourcesplugIns等的配置,并把得到的所有值封装到对象ModuleConfig对象(config)中 */

        List urls = splitAndResolvePaths(paths);
        URL url;

        for (Iterator i = urls.iterator(); i.hasNext();) {
            url = (URL) i.next();
            digester.push(config);
            this.parseModuleConfigFile(digester, url);
        }

        // 把config存储到servletContext中 属性名为Globals.MODULE_KEY

        getServletContext().setAttribute(Globals.MODULE_KEY
            + config.getPrefix(), config);

        return config;
    }

       

    ⑥用户资源文件的初始化 initModuleMessageResources(moduleConfig);

   

       protected void initModuleMessageResources(ModuleConfig config)
        throws ServletException {

        //从moduleConfig中读取所有的资源文件

        protected void initModuleMessageResources(ModuleConfig config)
        throws ServletException {
        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()
                    + "'");
            }

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

            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());
            getServletContext().setAttribute(mrcs[i].getKey()
                + config.getPrefix(), resources);
        }
    }
        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()
                    + "'");
            }

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

            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());
            getServletContext().setAttribute(mrcs[i].getKey()
                + config.getPrefix(), resources);
        }
    }

 

    ⑦用户插件的初始化 initModulePlugIns(moduleConfig); 

 

       protected void initModulePlugIns(ModuleConfig config)
        throws ServletException {
        if (log.isDebugEnabled()) {
            log.debug("Initializing module path '" + config.getPrefix()
                + "' plug ins");
        }

        // 从moduleConfig中读取所有的插件文件

        PlugInConfig[] plugInConfigs = config.findPlugInConfigs();
        PlugIn[] plugIns = new PlugIn[plugInConfigs.length];

        // 把所有plugIns存储到servletContext中

        getServletContext().setAttribute(Globals.PLUG_INS_KEY
            + config.getPrefix(), plugIns);

        for (int i = 0; i < plugIns.length; i++) {
            try {
                plugIns[i] =
                    (PlugIn) RequestUtils.applicationInstance(plugInConfigs[i]
                        .getClassName());
                BeanUtils.populate(plugIns[i], plugInConfigs[i].getProperties());

                // Pass the current plugIn config object to the PlugIn.
                // The property is set only if the plugin declares it.
                // This plugin config object is needed by Tiles
                try {
                    PropertyUtils.setProperty(plugIns[i],
                        "currentPlugInConfigObject", plugInConfigs[i]);
                } catch (Exception e) {
                    ;

                    // FIXME Whenever we fail silently, we must document a valid
                    // reason for doing so.  Why should we fail silently if a
                    // property can't be set on the plugin?

                    /**
                     * Between version 1.138-1.140 cedric made these changes.
                     * The exceptions are caught to deal with containers
                     * applying strict security. This was in response to bug
                     * #15736
                     *
                     * Recommend that we make the currentPlugInConfigObject part
                     * of the PlugIn Interface if we can, Rob
                     */
                }

                plugIns[i].init(this, config);
            } catch (ServletException e) {
                throw e;
            } catch (Exception e) {
                String errMsg =
                    internal.getMessage("plugIn.init",
                        plugInConfigs[i].getClassName());

                log(errMsg, e);
                throw new UnavailableException(errMsg);
            }
        }
    }

 

至此,ActionServlet的初始化工作完成! 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics