编程资料集中营
 | 网站首页 | 文章中心 | 编程资料2 | 软件下载 | BT下载 | 八卦星闻 | 音乐在线 | 在线游戏 | 免费电影 | 进入问吧 | 
Struts初始化, 我在几个月前曾经发表过一个帖子,就是和大家一起学习struts源代码。成为一名合格的程序员,阅读大量的优秀程序是必不可少的。只看书是不会让你水平有很大提高的,要多看多写。本来是打算等下面几篇文章写好后一起发布的,这样大家可能才能看得明白些,但是根据我现在的状况,估计还要一、两个月。所以,为了防止在struts源代码发生过大变化后我的文章就没有太大价值了,,
您现在的位置: 编程资料,学习资料,c,c++,vc,vc++,java,jsp,j2ee,j2me,asp,php >> 文章中心 >> JAVA 专区 >> Struts 技术 >> 文章正文
【字体:
Struts初始化   进入问吧

本站地址:http://www.bajiao123.com

作者:佚名    文章来源:不详    点击数:    更新时间:2007-4-19    

Struts初始化

我在几个月前曾经发表过一个帖子,就是和大家一起学习struts源代码。成为一名合格的程序员,阅读大量的优秀程序是必不可少的。只看书是不会让你水平有很大提高的,要多看多写。
本来是打算等下面几篇文章写好后一起发布的,这样大家可能才能看得明白些,但是根据我现在的状况,估计还要一、两个月。所以,为了防止在struts源代码发生过大变化后我的文章就没有太大价值了,所以就提前发表了,霍霍~~~
我的email为:mariah_fan@hotmail.com,有什么不对的地方请大家指正:)
struts作为J2EE的MVC框架已经取得了很大的成功,下面将分几篇文章说明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()释放内存。



ericli 2006-09-13 20:24 发表评论

   

进入问吧

本站地址:http://www.bajiao123.com

文章录入:admin    责任编辑:admin 
  • 上一篇文章:

  • 下一篇文章:
  • 高级搜索
    编程资料集中营