kapok
垃圾桶,嘿嘿,我藏的这么深你们还能找到啊,真牛!
BlogJava
::
首页
::
新随笔
::
联系
::
聚合
::
管理
::
455 随笔 :: 0 文章 :: 76 评论 :: 0 Trackbacks
<
2005年5月
>
日
一
二
三
四
五
六
24
25
26
27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
常用链接
我的随笔
我的评论
我的参与
最新评论
留言簿
(28)
给我留言
查看公开留言
查看私人留言
随笔分类
.NET(10)
(rss)
ALL(464)
(rss)
AppFuse(20)
(rss)
CorBa(2)
(rss)
Eclipse技巧和插件等(7)
(rss)
English(10)
(rss)
ERP(3)
(rss)
HibernateAndSpring(82)
(rss)
J2EE(290)
(rss)
J2SE(27)
(rss)
JB(2)
(rss)
JBOSS(4)
(rss)
JDO(1)
(rss)
Linux(7)
(rss)
Oracle(9)
(rss)
PetStore
(rss)
Struts(9)
(rss)
UML与RUP(13)
(rss)
Web Services(8)
(rss)
Weblogic Portal(72)
(rss)
XDoclet(6)
(rss)
个人项目所需资料(8)
(rss)
办公自动化(2)
(rss)
点滴(1)
(rss)
程序员生活(10)
(rss)
行业知识(15)
(rss)
软件工程和项目管理(32)
(rss)
软件测试(1)
(rss)
随手贴(5)
(rss)
面试(4)
(rss)
随笔档案
2005年9月 (18)
2005年8月 (39)
2005年7月 (42)
2005年6月 (49)
2005年5月 (70)
2005年4月 (116)
2005年3月 (121)
Corba
EAI
Bea Portal相关
dnnchina
Enterprise Java Research Library
xoops
泡泡-博客
Online Document
Bea Resource Center
WebLogic Online Help_ZH
Open Source
exo portal
Groller
Mule
pow2toolkit
xpetstore
开源
Portal
huihoo JSR168
灰狐
RSS Links
.Text 0.958 安装&问题解决方案
All about Blog and RSS
RSS links
Weblogic净化贴
Weblogic
WL Portal FAQs
WLP FAQss
不错的链接
chenyun2000
CSDN专栏作家
Eclipse Live Forum
firebody
gigix
glchengang
IT人
JavaEye
JavaPassion
michael
ODMG
oracle_tech
Pattern在线查询手册
querycriteria
rosen
spring reference
上海电子地图
兔八哥
兔子
思维导图
范凯的废纸篓
工具集合
AppFuse
数据仓库相关
blog on dw
BRM业务参考模型
chinabi
china-bi
CNOUG DW
datawarehouse
dbazine
dmreview
DW 信息目录
dw-institute
DWWAY
ewsolutions
flymouse
inmoncif
intelligententerprise
isomebody
IT售前论坛
rkimball
SummerRain
tdan
商业智能
头头脑脑
快语综合
精进门
搜索
最新评论
1. re: Java中的URLEncoder和URLDecoder类
asdfsdf
--sadf
2. re: 面试题,做出来3万月薪[未登录]
很强,就是这样的逻辑@此外
--TEST
3. re: MKS Toolkit[未登录]
政治
--s
4. re: Java 远程方法调用(RMI)
if (r instanceof Meeting )
这个Meeting从哪里来?
--nx
5. re: ClearCase指南-基础篇(连载一)
clearcase 可以使用clearfsimport -recurse -nsetevent进行批量导入
--china-java.net
阅读排行榜
1. weblogic部署方法(11445)
2. x509数字证书介绍(11414)
3. 一个很不错的基于角色的权限管理系统设计!(10485)
4. UML的StereoType的解释(9004)
5. When Runtime.exec() won't (5431)
6. 完全卸载Oracle(5392)
7. OpenLDAP快速指南(5099)
8. 如何发布和查找 WSDL 服务描述(4488)
9. Eclipse不能自动编译的问题(4276)
10. SSL※ X509(3867)
评论排行榜
1. 面试题,做出来3万月薪(11)
2. x509数字证书介绍(5)
3. OpenLDAP快速指南(5)
4. Compiere的汉化 (5)
5. oracle的select for update(4)
6. 使用Eclipse plus Pluto开发你的第一个与JSR168兼容的Portlet(3)
7. 迎接RFID的时代(3)
8. 简化JavaMail:小巧 Jakarta Commons-Email 简单教程(3)
9. Visual CHM和jd2chm不错(2)
10. Java 远程方法调用(RMI)(2)
struts源代码阅读(struts 初始化)
http://www.matrix.org.cn/article/1071.html
我在几个月前曾经发表过一个帖子,就是和大家一起学习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()释放内存。
posted on 2005-05-02 09:28
笨笨
阅读(1131)
评论(0)
编辑
收藏
所属分类:
J2EE
、
ALL
、
Struts
新用户注册
刷新评论列表
只有注册用户
登录
后才能发表评论。
网站导航:
博客园
IT新闻
知识库
C++博客
博问
管理
相关文章:
简化JavaMail:小巧 Jakarta Commons-Email 简单教程
读"Under the Hood of J2EE Clustering" J2EE集群
Phase
x509数字证书介绍
SSL※ X509
了解安全性断言标记语言
架构蓝图--软件架构 "4+1" 视图模型
主动对象
Profile,Stereotype,TaggedValue与OCL漫谈
Drools 为你的业务逻辑提供框架(翻译)
Powered by:
BlogJava
Copyright © 笨笨