在上一篇博客中讲到ActionServlet是如何初始化的以及web.xml的配置信息的具体作用。今天我们讲继续讲解ActionServlet在初始化的时候如何读取/WEB-INF/struts-config.xml信息到内存中,如何将这些从配置文件读取的信息以Actionmapping的形式展现在内存中的。
由于这部分内容是比较繁琐的,所以我对这部分的深入分析也不能太详细,但是具体实现流程我会讲清晰,如果有兴趣研究的童鞋们希望能够继续深入,研究的非常透彻的时候,可以给我发邮件或Q我。
下面来开始今天的博客,我们先从ActionServlet源代码的init方法开始。因为ActionServlet就是一个Servlet,它也是具有典型的那几个方法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)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) {
- // 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. Mostlikely, this is due to an "
- + "incorrect or missing library dependency.", t);
- throw new UnavailableException(t.getMessage());
- }
- }
在解释这段代码的流程和意思之前,有必要说一句,就是当我们在eclipse里面看代码的时候,尤其是看一段生疏的很长的代码的时候,希望能够经常使用Ctrl键(多余的不解释)。
下面开始讲解这段代码的流程和具体每一步的含义,如果有不正确的地方,希望指正。
首先映入眼帘的是initInternal()方法。这个方法的实现代码是:
代码段一:
- /**
- * <p>Initialize our internal MessageResourcesbundle.</p>
- *
- * @exception ServletException if we cannotinitialize these resources
- */
- protectedvoidinitInternal() throwsServletException {
- // :FIXME: Document UnavailableException
- try {
- internal = MessageResources.getMessageResources(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);
- }
代码段三:
- /**
- * 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);
- }
- }
这个方法的具体作用就是初始化MessageResources,具体实现是工厂模式,首先判断defaultFactory是否存在,不存在则创建工厂,
defaultFactory = MessageResourcesFactory.createFactory(),在通过工厂创建资源类defaultFactory.createResources(config);存在则直接创建资源类。
initOther()的方法,主要是初始化其它的配置,获取我们自己的struts-config配置文件的路径,
而它的默认路径就是web-inf/struts-config.xml,另外这个方法还会注册一些转换类的。具体源代码是:
- /**
- * <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 1.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);
- }
- }
initServlet()方法是利用digester读取web.xml文件并且放到servletContext中。具体实现源代码:
- /**
- * <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()) {
- log.debug("Mapping for servlet '" + servletName + "' = '" +
- servletMapping + "'");
- }
- if (servletMapping != null) {
- getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping);
- }
- }
这篇博客先介绍这几个方法,随着这些方法具体作用和具体实现的慢慢的我们就知道init方法的作用,也慢慢的就解开了当我们实例化ActionServlet的时候,digester是如何读取/WEB-INF/struts-config.xml的文件内容,并且放到了ActionMapping中。敬请期待!