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.loadC(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 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()释放内存。
分享到:
相关推荐
本资源“精通Java EE项目案例--基于Eclipse Spring Struts Hibernate (例子中的初始化SQL)”正是针对这样的集成环境提供了一套完整的数据库初始化语句,帮助开发者快速构建一个功能完善的Web应用。 首先,让我们...
本文将深入探讨Struts2的源码分析,特别是关于StrutsPrepareAndExecuteFilter的初始化过程,这是Struts2的核心组件之一,负责处理HTTP请求。 首先,我们来看`StrutsPrepareAndExecuteFilter`的初始化。这个过滤器...
下面我们将详细探讨如何实现这三个框架的集成,以及如何利用它们进行网站初始化和定时任务的设置。 首先,Struts2作为MVC框架,提供了强大的请求处理和视图展现功能。Struts2.3.8版本引入了一些新特性,如改进的...
这个过滤器的作用是在每个HTTP请求到达时执行Struts的初始化和执行流程,确保所有与Struts相关的处理逻辑都能够被正确执行。 ### 3. Action类(userAction.java) `userAction`类是Struts中的一个Action类,它继承...
在本篇文章中,我们将深入探讨Struts2的核心组件、配置方法以及如何在给定的环境中(MyEclipse 6.0、JDK 1.5、Tomcat 5.5)使用和配置Struts2的jar包。 1. **Struts2核心组件**: - **Action类**:是业务逻辑处理...
《Struts2技术内幕:深入解析Struts2架构设计与实现原理》由国内极为资深的...运行主线篇首先对Struts2的两大运行主线——初始化主线和HTTP请求处理主线进行了深入的剖析,然后对Struts2的扩展机制进行了解读和抽象
《Struts2技术内幕:深入解析Struts2架构设计与实现原理》由国内极为资深的...运行主线篇首先对Struts2的两大运行主线——初始化主线和HTTP请求处理主线进行了深入的剖析,然后对Struts2的扩展机制进行了解读和抽象。
本文将深入探讨Struts2中的常量配置,这些常量在框架的运行时扮演着至关重要的角色。 首先,我们要了解Struts2配置文件的层次结构。主要有以下几个核心配置文件: 1. **struts-default.xml**:这是Struts2核心库中...
本教程将深入探讨Struts2的核心概念、架构以及实际开发中的应用。 一、Struts2概述 Struts2是Apache软件基金会下的一个开源项目,它继承了Struts1的优秀特性,并融合了WebWork框架的优点。Struts2的目标是提供一个...
这里我们将深入探讨Struts2国际化源码的实现及其工作原理。 国际化(i18n)是软件开发中的一个术语,意指设计和实施能够适应不同语言和文化环境的系统。在Web应用中,这通常涉及资源文件,如.properties文件,其中...
下面我们将深入探讨Struts1的相关知识点。 1. **MVC模式**:MVC模式是软件工程中的一种设计模式,将业务逻辑(Model)、用户界面(View)和数据控制(Controller)分离,使得代码更易维护和扩展。在Struts1中,...
本书由国内极为资深的Struts2技术专家(网名:downpour)亲自执笔,iteye兼...运行主线篇首先对Struts2的两大运行主线——初始化主线和HTTP请求处理主线进行了深入的剖析,然后对Struts2的扩展机制进行了解读和抽象。
下面我们将深入探讨Struts2的关键概念、注释以及使用方法。 **1. Struts2架构** Struts2的核心是Action类,它是处理用户请求的入口点。每个Action对应一个业务逻辑,当用户发起请求时,Struts2会根据配置文件(如...
在本讲义中,我们将深入探讨Struts2的基本概念、依赖的库、启动配置以及配置文件。 首先,开发Struts2应用需要依赖一些核心的JAR文件。这些文件包括: 1. `struts2-core-2.x.x.jar`:这是Struts2框架的核心库,...
在本文中,我们将深入探讨Struts1.2框架的核心特性、它如何工作以及它对Java Web开发的重要性。 1. **MVC模式**:Struts1.2遵循MVC设计模式,将应用程序的业务逻辑、视图呈现和用户交互分离开来,使得代码更加模块...
下面我们将深入探讨Struts2监听器的使用及其在实际开发中的作用。 首先,了解监听器在Web应用中的基本概念。监听器是Servlet容器(如Tomcat)中的特殊Java类,它们实现了特定的监听器接口,并在特定事件发生时被...
内容简介 出版日期: 2012年1月10日 《Struts2技术内幕:深入解析Struts2架构...运行主线篇首先对Struts2的两大运行主线——初始化主线和HTTP请求处理主线进行了深入的剖析,然后对Struts2的扩展机制进行了解读和抽象。
下面我们将深入探讨Struts1.2的一些主要知识点。 1. **MVC设计模式**:MVC模式将应用程序分为三个部分——模型(Model)、视图(View)和控制器(Controller)。在Struts1.2中,模型处理业务逻辑,视图负责用户界面...
ActionServlet在初始化时会读取配置文件(struts-config.xml),并根据配置创建ActionForm和Action的实例。 2. **ActionMapping**:这个类定义了请求与Action类之间的映射关系。它包含了ActionForm和Action的路径...