Struts
的资源文件时如何初始化的
|-----------------------------------------------------------------------------------------------------|
|
作者:zhyiwww
zhyiwww@163.com
|
| 转载请注明出处 |
|-----------------------------------------------------------------------------------------------------|
分以下几步来理解:
[1]
Web
应用如何知道使用的是
Struts
我们知道,在
Web
工程的
/WEB-INF/
目录下面,我们有两个配置文件
Web.xml
和
Struts-config.xml.
一般情况下就只有一个
web.xml
文件,如果系统是用了
struts
技术的话,那么就会有
struts-config.xml
文件。
[2]
系统是如何启动和初始化
struts
的
在
Web.xml
中有这么一段代码:
<
servlet
>
<
servlet-name
>
action
</
servlet-name
>
<
servlet-class
>
org.apache.struts.action.ActionServlet
</
servlet-class
>
<
init-param
>
<
param-name
>
config
</
param-name
>
<
param-value
>
/WEB-INF/struts-config.xml
</
param-value
>
</
init-param
>
<
init-param
>
<
param-name
>
debug
</
param-name
>
<
param-value
>
3
</
param-value
>
</
init-param
>
<
init-param
>
<
param-name
>
detail
</
param-name
>
<
param-value
>
3
</
param-value
>
</
init-param
>
<
load-on-startup
>
0
</
load-on-startup
>
</
servlet
>
<
servlet
>
<
servlet-name
>
startThread
</
servlet-name
>
<
servlet-class
>
com.cgogo.ypindex.StartThread
</
servlet-class
>
<
init-param
>
<
param-name
>
startParam
</
param-name
>
<
param-value
>
2
</
param-value
>
</
init-param
>
<
load-on-startup
>
1
</
load-on-startup
>
</
servlet
>
<
servlet-mapping
>
<
servlet-name
>
action
</
servlet-name
>
<
url-pattern
>
*.do
</
url-pattern
>
</
servlet-mapping
>
在
web.xml
中会配置
struts
的中央控制器类。
Web.xml
配置文件的初始化是由容器来实现载入和初始化的。如果你使用的是
tomcat
的话,那么就是由
tomcat
在启动的时候会载入此
web.xml
文件,也就为此
web
应用创建了一个
web Context,
此
context
也就是你
Web
应用的访问入口。
载入中央控制器
org.apache.struts.action.ActionServlet
,这是一个
Servlet,
那么,其就要进行
servlet
的初始化操作。此
action
是如何对
Struts
系统进行初始化的呢?
[3]
init()--
ActionServlet
如何初始化
Struts
系统?
看一下
ActionServlet
的源代码:
我们知道,在一个
Servlet
中,在其启动的时候,首先要执行
init()
方法,那么我们先来看一下
actionServlet
的
init()
方法的源代码:
/**
* <p>Initialize this servlet. Most of the processing has been factored into
* support methods so that you can override particular functionality at a
* fairly granular level.</p>
*
* @exception ServletException if we cannot configure ourselves correctly
*/
public void init() throws ServletException {
// Wraps the entire initialization in a try/catch to better handle
// unexpected exceptions and errors to provide better feedback
// to the developer
try {
(1)
initInternal();
(2)
initOther();
(3)
initServlet();
getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
(4)
initModuleConfigFactory();
// Initialize modules as needed
ModuleConfig moduleConfig = initModuleConfig("", config);
(5)
initModuleMessageResources(moduleConfig);
(6)
initModuleDataSources(moduleConfig);
(7)
initModulePlugIns(moduleConfig);
moduleConfig.freeze();
(8)
初始化配置参数
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. Most likely, this is due to an "
+ "incorrect or missing library dependency.", t);
throw new UnavailableException(t.getMessage());
}
}
先来看一下初始化(
1
)的部分
initInternal()
。
[4]
initInternal()--
内部资源文件的初始化
initInternal()
就是实现内部资源文件的初始化的,也就是转为
Struts
系统本身提供的以下错误信息提示等文字的国际化实现的。我们看一下源代码是如何实现的:
/**
*
<p>
Initialize
our
internal
MessageResources
bundle.
</p>
*
*
@exception
ServletException
if
we
cannot
initialize
these
resources
*/
protected
void
initInternal()
throws
ServletException {
// :
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
+
"'"
);
}
}
Struts
根据配置文件的名字得到一个资源文件。
internalName
就是内部资源文件的名称,其在
actionServlet
中定义:
/**
*
<p>
The
Java
base
name
of
our
internal
resources.
</p>
*
@since
Struts
1.1
*/
protected
String
internalName
=
"org.apache.struts.action.ActionResources"
;
取得后的对象是一个
MessageResources
的对象,保存在
internal
中,
/**
* <p>The resources object for our internal resources.</p>
*/
protected MessageResources internal = null;
经过此初始化后,
internal
就不在是
null
了。
至此就实现完成了内部资源文件的初始化。如果出现了异常的话,那么系统就捕捉到。
然后,系统就开始初始化其它的配置,即(
2
)
initOther();
[5]
initOther()--
如何初始化其他的配置的?
/**
* <p>Initialize other global characteristics of the controller servlet.</p>
*
* @exception ServletException if we cannot initialize these resources
*/
protected void initOther() throws ServletException {
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);
}
}
然后就执行(
3
)
initServlet();
[6]
initServlet()--
如何初始化
servlet
这个初始化主要是初始化
servlet
的,哪些
servlet
呢?就是我们在
web.xml
中配置的那些需要在
web application
初始化时就栽入系统的
servlet
这是一个复杂的过程:
我的理解:
这部分代码就执行一次,仅在初始化的时候执行一次。
/**
* <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
//
这里保存当前的servlet名字,保存在actionServlet的servletName属性中
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);
}
}
[7]
初始化其他模块
(1)
初始化工厂
getServletContext().setAttribute(
Globals
.
ACTION_SERVLET_KEY
,
this
);
initModuleConfigFactory();
(2)
初始化资源模块
// Initialize modules as needed
ModuleConfig moduleConfig = initModuleConfig(
""
,
config
);
initModuleMessageResources(moduleConfig);
(3)
初始化数据源配置模块
initModuleDataSources(moduleConfig);
(4)
初始化
PlugIn
模块
initModulePlugIns(moduleConfig);
moduleConfig.freeze();
[8]
初始化参数
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();
}
[9]
我也不知道做什么用的
this
.initModulePrefixes(
this
.getServletContext());
this
.destroyConfigDigester();
以上就是Struts的初始化流程。
[10]
部分模块的详细实现:
a.
工厂的初始化如何实现的:
/**
* <p>Initialize the factory used to create the module configuration.</p>
* @since Struts 1.2
*/
protected void initModuleConfigFactory(){
/**
这个部分的代码就是取得参数。
这个参数你可以自己扩展你的模块实现工厂。但是一般都没有自己去做。
所以一般都使用的默认的工厂初始化配置。
*/
String configFactory = getServletConfig().getInitParameter("configFactory");
/**
下面的代码,只有你做了自己的配置才会有效。否则一般是不执行的。
*/
if (configFactory != null) {
/**
设置此工厂,并把其参数存入到
ModuleConfigFactory.factoryClass
属性中。
此部分可以看
ModuleConfigFactory
的代码。
ModuleConfigFactory
是一个
*/
ModuleConfigFactory.setFactoryClass(configFactory);
}
}
b.
资源模块式如何初始化的
//
调用的部分
protected String config = "/WEB-INF/struts-config.xml";
------------------------------------------------------------------
ModuleConfig moduleConfig = initModuleConfig("", config);
initModuleMessageResources(moduleConfig);
//
实现的部分:
protected void
initModuleMessageResources
(ModuleConfig config)
throws ServletException {
/**
在
struts-config.xml
中的资源文件配置,你可能配置了多个资源,所以此处取得是一个数组
*/
MessageResourcesConfig
mrcs[]
= config.findMessageResourcesConfigs();
for (int i = 0; i < mrcs.length; i++) {
if ((mrcs[i].getFactory() == null)
|| (mrcs[i].getParameter() == null)) {
continue;
}
if (log.isDebugEnabled()) {
log.debug(
"Initializing module path '"
+ config.getPrefix()
+ "' message resources from '"
+ mrcs[i].getParameter()
+ "'");
}
/**
protected String factory =
"org.apache.struts.util.PropertyMessageResourcesFactory";
就是返回的这个值,如果你没有做其他的设置的话。
一般情况下,我们都用得是默认的
*/
String factory = mrcs[i].getFactory();
/**
此处对每一个资源配置文件都回去创建一个工厂
*/
MessageResourcesFactory.setFactoryClass(factory);
MessageResourcesFactory factoryObject =
MessageResourcesFactory.createFactory();
factoryObject.setConfig(mrcs[i]);
MessageResources
resources
=
factoryObject.createResources(mrcs[i].getParameter());
resources.setReturnNull(mrcs[i].getNull());
resources.setEscape(mrcs[i].isEscape());
/**
这一部分非常重要。
我们之所以能够直接调用,就是因为,初始化后,我们就把此
resources
放到了其对应的当前应用的属性值里面了。之后我们就可以直接调用了。
*/
getServletContext().setAttribute(
mrcs[i].getKey() + config.getPrefix(),
resources);
}
}
c.
数据模块是如何初始化的
==========================================================
//
调用部分
initModuleDataSources(moduleConfig);
//
实现部分:
/**
* <p>Initialize the data sources for the specified module.</p>
*
* @param config ModuleConfig information for this module
*
* @exception ServletException if initialization cannot be performed
* @since Struts 1.1
*/
protected void initModuleDataSources(ModuleConfig config) throws ServletException {
// :FIXME: Document UnavailableException?
if (log.isDebugEnabled()) {
log.debug("Initializing module path '" + config.getPrefix() +
"' data sources");
}
ServletContextWriter scw =
new ServletContextWriter(getServletContext());
/**
因为你可能配置了多个数据源,所以此处返回的是一个数组
*/
DataSourceConfig dscs[] = config.findDataSourceConfigs();
//
处理没有配置数据源的情况
if (dscs == null) {
dscs = new DataSourceConfig[0];
}
/**
/**
* <p>The JDBC data sources that has been configured for this module,
* if any, keyed by the servlet context attribute under which they are
* stored.</p>
*/
protected FastHashMap dataSources = new FastHashMap();
这是一个加工过的
HashMap
,又不同的工作模式
*/
dataSources.setFast(false);
for (int i = 0; i < dscs.length; i++) {
if (log.isDebugEnabled()) {
log.debug("Initializing module path '" + config.getPrefix() +
"' data source '" + dscs[i].getKey() + "'");
}
DataSource ds = null;
try {
/**
*/
ds = (DataSource)
RequestUtils.applicationInstance(dscs[i].getType());
BeanUtils.populate(ds, dscs[i].getProperties());
ds.setLogWriter(scw);
} catch (Exception e) {
log.error(internal.getMessage("dataSource.init", dscs[i].getKey()), e);
throw new UnavailableException
(internal.getMessage("dataSource.init", dscs[i].getKey()));
}
/**
这一个部分很重要。
把初始化后的数据源放入到
servlet
的属性中,所以我们才可以通过
struts
的对应属性直接访问。
protected String key = Globals.DATA_SOURCE_KEY;
所以,我们可以通过
Globals.DATA_SOURCE_KEY
属性的值来取得其配制后的数据源。
如果多个的话,可以通过数据源的参数
ID
来配置和调用。
*/
getServletContext().setAttribute
(dscs[i].getKey() + config.getPrefix(), ds);
dataSources.put(dscs[i].getKey(), ds);
}
dataSources.setFast(true);
}
至此,Struts系统初始化完毕。
|----------------------------------------------------------------------------------------|
版权声明 版权所有 @zhyiwww
引用请注明来源 http://www.blogjava.net/zhyiwww
|----------------------------------------------------------------------------------------|
posted on 2006-12-25 16:47
zhyiwww 阅读(3353)
评论(1) 编辑 收藏 所属分类:
j2ee