`
cui09
  • 浏览: 115390 次
  • 性别: Icon_minigender_1
  • 来自: 吉林
最近访客 更多访客>>
社区版块
存档分类
最新评论

struts源代码阅读(struts 初始化)

阅读更多
第一篇  struts的初始化

struts 的核心类是org.apache.struts.action.ActionServlet,这个类将会在struts第一次使用时,
作为servlet初始化并存入tomcat容器。很显然的,初始化将会调用init方法初始化相应的数据。

一、initInternal()方法:
    通过调用MessageResources.getMessageResources(internalName)方法生成一个
    MessageResources类,getMessageResources是通过调用MessageResourcesFactory.
    createResources(config)来实现的。至于MessageResourcesFactory是一个abstract类,任何
    继承自它的类都要实现createResources方法,生成MessageResources对象。整个程序生成
    MessageResourcesFactory使用了如下技巧:
    MessageResourcesFactory.factoryClass = factoryClass;
    MessageResourcesFactory.clazz = null;
    首先会通过factoryClass来定义一个类全名,然后通过ClassLoader.loadClass
    (factoryClass)方法来生成这个类,并赋给clazz,然后通过newInstance来生成一个对象。
    在本程序中,生成MessageResources对象实际就是对如下属性进行了初始化:
    this.factory = factory;("org.apache.struts.util.PropertyMessageResourcesFactory")
    this.config = config;("org.apache.struts.action.ActionResources")
    this.returnNull = returnNull;(true/false)

    对于MessageResources类的作用是根据不同的Locate来格式化相应的string。或者把你需要改变
    的string存放到数组中,然后通过getMessage(Locale locale, String key, Object args[])
    方法来格式化。然后把格式好的string存放到HashMap里,这样就可以为以后重用。这里的key是
    使用的locale.toString() + "." + key

    在PropertyMessageResources中的loadLocale方法用来读取resource的初始化信息。首先它会
    通过一个HashMap检测这个localKey相关的message是否已经被初始化了,如果被初始化过就跳
    出,检测的方法是locales.get(localeKey) != null。
    然后会读取如下一个文件:
    org/apache/struts/action/ActionResources_(localKey).properties,然后进行如下操作:
    Properties props = new Properties();
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    is = classLoader.getResourceAsStream(name);
    props.load(is);
    Iterator names = props.keySet().iterator();
        while (names.hasNext()) {
            String key = (String) names.next();
            if (log.isTraceEnabled()) {
                log.trace("  Saving message key '" + messageKey(localeKey, key));
            }
            messages.put(messageKey(localeKey, key), props.getProperty(key));
    }

    PropertyMessageResources 就是通过上面的loadLocale方法查找与Locale locale, String key
    相对对应的Message.查找的次序如下locale.toString(),然后是
    localeKey = localeKey.substring(0, underscore),然后是defaultLocale,然后是key。

    最后,resource类的结构如下:
    PropertyMessageResources extends MessageResources
    PropertyMessageResourcesFactory extends MessageResourcesFactory

二、initOther()方法:
    从servlet中获取config和debug两个参数,然后初始化ConvertUtils对象。由于
    ConvertUtils.deregister()的初始化,所有的Converter都是有初始值的,所以这里Struts自己
    把这些初始值设置为null,即转换出错的时候返回null,而不是初始值。使用ConvertUtils类的
    原因是由于从form传输过来的都是String类型的值,所以我们要把它们转换成相应的类型。

    提到几个技巧:
    *public boolean isIndexed() {
         if (type == null) {
             return (false);
         //技巧一:判断是否是一个Array类的方法
         } else if (type.isArray()) {
             return (true);
         //技巧二:判断type是否是List的一个父类或者父接口,或者与List为同一个类
         //要注意如果List是另一个primitive的TYPE类,那么type必须也是这个类才会
         //返回true,否则都是false。注意long.TYPE与Long.class是不同的
         } else if (List.class.isAssignableFrom(type)) {
             return (true);
         } else {
            return (false);
         }
     }

    *//componentType为Array类所存储的元素的类别
     Class componentType = indexedProperty.getClass().getComponentType();
     //生成一个新的Array
     Object newArray = Array.newInstance(componentType, (index + 1));
     System.arraycopy(indexedProperty, 0, newArray, 0, length);
     indexedProperty = newArray;
     set(name, indexedProperty);
     int newLength = Array.getLength(indexedProperty);
     for (int i = length; i < newLength; i++) {
        Array.set(indexedProperty, i, createProperty(name+"["+i+"]", componentType));
     }

三、initServlet()方法:
    这个方法主要是通过digester类解析web.xml,对String servletMapping属性进行初始化。对于
    digester说明如下:这是一个基于DOM的SAX实现的类,它是事件触发的,根据xml文件的结构,
    每次读到一个节点元素就会触发一个事件。

    InputStream input = getServletContext().getResourceAsStream("/WEB-INF/web.xml");
    这是一个比较少见的方法。首先通过this.servletName = getServletConfig().
    getServletName()获取servlet的名称,然后根据
    if (servletName.equals(this.servletName)) {
        this.servletMapping = urlPattern;
    }
    来判断当前读到的servlet名称是否是我们运行的servlet的名称,如果是,就把url-pattern作为
    我们的servletMapping。

四、getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this)
    把自己存储到servletContext中,属性名为Globals.ACTION_SERVLET_KEY。

五、ModuleConfig moduleConfig = initModuleConfig("", config)
    这个方法使用由initOther()方法获取的config值为要解析的xml路径,用来初始化ModuleConfig。
    它首先采用与生成MessageResourcesFactory同样的方法产生一个MessageResourcesFactory对象:
    MessageResourcesFactory为一个抽象类,每一个继承它的类都要实现
    createModuleConfig(String prefix)方法。本程序使用的缺省的MessageResourcesFactory类为
    org.apache.struts.config.impl.DefaultModuleConfigFactory,它
    的createModuleConfig(String prefix)方法会生成一个ModuleConfigImpl类。

    ModuleConfigImpl类相当于一个JavaBean,用来存放一个web模块运行时所需要的配置信息。当
    然,一个web模块可以拥有多个ModuleConfig,但是缺省的是prefix长度为0的ModuleConifg。它
    的每个属性几乎都是由HashMap组成的,它通过一个configured布尔值来描述当前的ModuleConfig
    是否已经被初始化完毕,在每存放一个属性的时候都会监测这个值。如果初始化完毕而还要改变
    里面的属性值,则会报出IllegalStateException("Configuration is frozen")异常,现在对它
    的属性简单说明如下:
    * protected HashMap actionConfigs:
      这个HashMap用来存储ActionConfig对象。
    * protected HashMap dataSources
      这个HashMap用来存储DataSourceConfig对象。
    * protected HashMap exceptions
      这个HashMap用来存储ExceptionConfig对象。
    * protected HashMap formBeans
      这个HashMap用来存储FormBeanConfig对象。
    * protected HashMap forwards
      这个HashMap用来存储ForwardConfig对象。
    * protected HashMap messageResources
      这个HashMap用来存储MessageResourcesConfig对象。
    * protected ArrayList plugIns
      这个HashMap用来存储PlugInConfig对象。
    * protected ControllerConfig controllerConfig
      ControllerConfig类
    * protected boolean configured
      标志这个ModuleConfig是(true)否(false)配置完成。
    * protected String prefix
      用来标志和区分ModuleConfig类,同时在使用上面的config类初始化相应的资源以后,也是通
      过这个prefix来区分所属的不同的web模块。
    * protected String actionMappingClass = "org.apache.struts.action.ActionMapping"
      ActionMapping类名,缺省为org.apache.struts.action.ActionMapping。

    初始化ModuleConfig的方法如下:
    首先是使用getServletConfig().getInitParameter("mapping")来获取设定的ActionMapping类
    名,然后通过initConfigDigester()方法来生成一个digester。最后用","分隔config,对每一
    块调用parseModuleConfigFile(prefix, paths, config, digester, path)方法解析。注意,这
    个方法实际上只有两个参数是有意义的:path为我们要解析的xml文件,config用来初始化完成
    后保存到servletContext中。

    如果ModuleConfig中存放的FormBeanConfig为Dydamic类型,那么就调用
    DynaActionFormClass.createDynaActionFormClass(FormBeanConfig)初始化
    DynaActionFormClass,并存放到DynaActionFormClass.dynaClasses 的 static HashMap中。这
    里的key为FormBeanConfig.getName() + moduleConfig.getPrefix()。
    
    如果当前的ModuleConfig为缺省的ModuleConfig,那么将会调用如下几个方法:
    defaultControllerConfig(config)
    defaultMessageResourcesConfig(config)
    defaultFormBeansConfig(config)
    defaultForwardsConfig(config)
    defaultMappingsConfig(config)
    在struts1.1以后,这个特例将会被废弃:

    defaultControllerConfig(config)为ControllerConfig通过getInitParameter(s)方法初始化如
    下几个属性:bufferSize,content,locale(true/false),maxFileSize,nocache(true/false)
    ,multipartClass,tempDir。

    defaultMessageResourcesConfig(config)为MessageResourcesConfig通过getInitParameter(s)
    方法初始化如下几个属性:application,factory,null(true/false)。

    其它的几个方法就是获取不同的对象,然后把它们相应的存储到servlet中。关心如下:
    ActionFormBeans=>FormBeanConfig,ActionForwards=>ForwardConfig,
    ActionMappings=>ActionConfig。

六、initModuleMessageResources(ModuleConfig config)
    通过存储在ModuleConfig中的MessageResourcesConfig对象,逐个初始化MessageResource,
    然后再把初始化好的MessageResources存放到ServletContext中,attributeName为
    MessageResourcesConfig.getKey() + ModuleConfig.getPrefix()。

七、initModuleDataSources(ModuleConfig config)
    通过存储在ModuleConfig中的DataSourceConfig对象,逐个初始化DataSource。然后对于每一个
    DateSource通过BeanUtils.populate(ds, dscs[i].getProperties())方法初始化其属性。再把初
    始化好的DateSource存放到ServletContext中,attributeName为
    DataSourceConfig.getKey() + ModuleConfig.getPrefix()。同时也存放到名位dataSources的
    FastHashMap中,key为DataSourceConfig.getKey()。

    这里还会根据生成的DateSource对象是否是GenericDataSource类型,如果是则调用
    GenericDataSource.open()方法。GenericDataSource是一个非常简单的数据库连接池,它的
    open()方法用来初始化连接池,生成最小数目的GenericConnection,这里的open()方法根据
    String driver变量是否为null来判断是否已经被初始化过。需要仔细说明的是getConnection()
    方法,它首先从连接池中取出GenericConnection对象,然后检查其是否是可链接的,如果是就
    返回,否则继续取出,同时activeCount-1。如果没有取到,则会检查当前可使用的
    GenericConnection是否达到最大值(activeCount < maxCount),如果没有,调用
    createConnection()方法声成一个新的GenericConnection,然后检查其是否是可链接,如果可以
    则返回。returnConnection(GenericConnection conn)方法则是通过把GenericConnection放回到
    连接池,然后activeCount-1。

    这个方法中使用到了ServletContextWriter类,DateSource的log信息就通过这个类写入。对这个
    类说明如下:
    它继承自PrintWriter,而PrintWriter又继承自Writer。Writer类所作的事情就是在同步的情况下
    调用abstract方法:abstract public void write(char cbuf[], int off, int len),这个方法
    将会根据调用者的需要由调用者实现。
    PrintWriter则首先通过ensureOpen()方法检验这个类中是否有写入的对象(Writer类或其子类),
    如果有则根据不同的情况调用这个写入对象的write方法(out.write(....))。这个类的print(...)
    方法就是据不同的情况调用相应的write(...)方法。而println(...)与之的区别就是每次多写入一
    个换行字符串。还有一个区别是println(...)会根据是否需要autoflush进行flush,而write(...)
    方法不会。
    ServletContextWriter类的作用是把字符写入ServletContext中。ServletContextWriter类方法中
    真正实现了write方法:
    public void write(char c) {
        if (c == '/n')
            flush();
        else if (c != '/r')
            buffer.append(c);
    }
    public void flush() {
        if (buffer.length() > 0) {
            context.log(buffer.toString());
            buffer.setLength(0);
        }
    }

八、initModulePlugIns(moduleConfig)
    通过存储在ModuleConfig中的PlugInConfig对象,逐个初始化PlugIn对象,存放到一个数组中,
    然后再把这个数组存放到ServletContext中,attributeName为
    Globals.PLUG_INS_KEY + ModuleConfig.getPrefix()。

    对每一个生成的PlugIn对象通过
    BeanUtils.populate(plugIns[i], plugInConfigs[i].getProperties())方法初始化其属性。然后
    再把PlugInConfig对象存放到由其生成的PlugIn对象中。

    最后,通过plugIns[i].init(this, (ModuleConfig) config)初始化这个plugIn对象。

九、初始化结束
    完成了这个初始化以后,会调用ModuleConfig.freeze()令这个ModuleConfig变得不可改变。然后
    会遍历ServletConfig中的initParameterNames,如果有以"config/"开头的,则通过这个parameter
    的值继续初始化其它的ModuleConfig,且这个ModuleConfig的prefix为"config/"后的字符串。
    
    同样调用如下方法:
    initModuleMessageResources(moduleConfig);
    initModuleDataSources(moduleConfig);
    initModulePlugIns(moduleConfig);
    moduleConfig.freeze();

    最后调用destroyConfigDigester()释放内存。
分享到:
评论

相关推荐

    struts2源代码分析

    Struts2的设计思路和工作流程与Struts1.x有很大的区别,这使得深入理解其源代码变得至关重要。 在分析Struts2的源代码之前,你需要首先获取Struts2的源代码,可以通过访问...

    struts1源代码

    8. **PlugIn**:允许开发者插入自定义的初始化和销毁代码,以扩展Struts1的功能。 9. **Interceptor**:拦截器是Struts1中实现AOP(面向切面编程)的重要机制,可以定义在请求处理之前和之后执行的逻辑,例如日志...

    Struts源代码阅读.CHM

    Struts 初始化 initInternal()方法: initOther()方法 initServlet()方法 getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this) ModuleConfig moduleConfig = ...

    struts1.1源代码

    通过阅读 Struts 1.1 的源代码,我们可以更深入地理解其内部工作原理,比如请求处理流程、对象的创建和管理、异常处理机制等。对于有基础的开发者来说,这有助于提升应用开发的效率和质量,更好地解决实际问题。希望...

    一个很好的struts+hibernate源代码示例

    首先,`testFrame.sql`文件通常包含了示例项目的数据库初始化脚本,这可能包括创建表结构、填充初始数据等操作。开发者需要导入这个SQL文件到数据库中,为应用程序设置好数据环境。 Hibernate的核心在于它的配置...

    一个很好的struts源代码示例

    这个"一个很好的struts源代码示例"提供了一个全面的教程,帮助开发者了解如何在实际项目中使用Struts进行数据操作,包括增、删、改、查(CRUD)的基础功能。 1. **Struts框架基础**:Struts框架的核心是Action...

    struts1.2源代码及文档

    6. **性能优化**:通过阅读源代码,我们可以找到一些性能瓶颈,例如ActionForm的缓存策略,以及ActionServlet的线程安全问题。 7. **安全性**:Struts1.2存在一些已知的安全漏洞,比如XSS和CSRF,通过研究源代码,...

    Struts1.3源代码

    - 如何配置和初始化Struts框架。 - 控制器如何处理请求并调度业务逻辑。 - 如何设计和实现ActionForm来处理用户输入。 - Action类如何与Service层交互,执行业务逻辑。 - Tiles如何帮助构建复杂的页面结构。 - 如何...

    基于struts的bbs源代码

    5. **源代码开放性**:开源的源代码意味着任何人都可以查看、学习和修改代码,这对于初学者来说是一个很好的学习资源,可以通过阅读源代码理解Struts框架的实际运用,以及BBS系统的具体实现。 6. **BBS功能**:基本...

    struts2源代码

    3. **StrutsPrepareAndExecuteFilter**:过滤器负责初始化Struts2的配置并处理请求。 4. **StrutsTagLib**:提供了一系列JSP标签,简化视图层的开发。 5. **Plug-in机制**:Struts2允许通过插件来扩展功能,如国际化...

    struts1.x 最简洁国际化 源代码

    - 这告诉Struts在初始化时查找名为`ApplicationResources.properties`的资源包。 6. **控制器逻辑**: - 在Action类中,可以通过`ActionContext`获取当前的`Locale`,并根据它加载对应的资源包。然后,Action可以...

    struts源代码

    Struts源代码的分析和理解对于Java开发者来说至关重要,因为它可以帮助他们深入理解Web应用的架构设计,提高开发效率,并能够自定义和扩展框架功能。 1. **MVC模式**: MVC模式是Struts的核心,它将应用程序分为...

    struts(源代码)-1.2.7-src

    通过阅读这些源代码,你可以了解到Struts如何处理请求、如何与数据库交互、如何进行表单验证以及如何构建动态页面。这对于深入理解MVC模式和Java Web开发有极大的帮助,也为你在实际项目中使用或优化Struts提供基础...

    struts2 源代码

    源码中会有许多预定义的拦截器实现,例如`PrepareInterceptor`用于初始化Action,`ExceptionMappingInterceptor`处理异常。 4. **插件(Plugins)**:Struts2支持插件化开发,如Struts2-dojo-plugin提供了丰富的...

Global site tag (gtag.js) - Google Analytics