Struts 的資源文件時如何初始化的
|-----------------------------------------------------------------------------------------------------|
|????? ???????? ???????????? ?? ?
作者:zhyiwww
???????zhyiwww@163.com??????
????????????? ???? |
|???????????????????????????????????????????????????轉(zhuǎn)載請注明出處?????????????????????????????????????????? |
|-----------------------------------------------------------------------------------------------------|
分以下幾步來理解:
[1] Web 應(yīng)用如何知道使用的是 Struts
我們知道,在
Web
工程的
/WEB-INF/
目錄下面,我們有兩個配置文件
Web.xml
和
Struts-config.xml.
一般情況下就只有一個
web.xml
文件,如果系統(tǒng)是用了
struts
技術(shù)的話,那么就會有
struts-config.xml
文件。
[2] 系統(tǒng)是如何啟動和初始化 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
配置文件的初始化是由容器來實現(xiàn)載入和初始化的。如果你使用的是
tomcat
的話,那么就是由
tomcat
在啟動的時候會載入此
web.xml
文件,也就為此
web
應(yīng)用創(chuàng)建了一個
web Context,
此
context
也就是你
Web
應(yīng)用的訪問入口。
載入中央控制器
org.apache.struts.action.ActionServlet
,這是一個
Servlet,
那么,其就要進行
servlet
的初始化操作。此
action
是如何對
Struts
系統(tǒng)進行初始化的呢?
[3] init()-- ActionServlet 如何初始化 Struts 系統(tǒng)?
看一下
ActionServlet
的源代碼:
我們知道,在一個
Servlet
中,在其啟動的時候,首先要執(zhí)行
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)?????
初始化配置參數(shù)
??????????? 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()--
內(nèi)部資源文件的初始化
initInternal()
就是實現(xiàn)內(nèi)部資源文件的初始化的,也就是轉(zhuǎn)為
Struts
系統(tǒng)本身提供的以下錯誤信息提示等文字的國際化實現(xiàn)的。我們看一下源代碼是如何實現(xiàn)的:
???
/**
????
*
<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 根據(jù)配置文件的名字得到一個資源文件。
internalName
就是內(nèi)部資源文件的名稱,其在
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;
經(jīng)過此初始化后, internal 就不在是 null 了。
至此就實現(xiàn)完成了內(nèi)部資源文件的初始化。如果出現(xiàn)了異常的話,那么系統(tǒng)就捕捉到。
然后,系統(tǒng)就開始初始化其它的配置,即(
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);
??????? }
}
然后就執(zhí)行(
3
)
initServlet();
[6]
?
initServlet()--
如何初始化
servlet
這個初始化主要是初始化 servlet 的,哪些 servlet 呢?就是我們在 web.xml 中配置的那些需要在 web application 初始化時就栽入系統(tǒng)的 servlet
這是一個復(fù)雜的過程:
我的理解:
??????
這部分代碼就執(zhí)行一次,僅在初始化的時候執(zhí)行一次。
?????? ??? /**
???? * <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
?????? //
這里保存當(dāng)前的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");
??????? }
? ??// 取得當(dāng)前的配置文件???
InputStream input =
??????????? getServletContext().getResourceAsStream("/WEB-INF/web.xml");
??????? if (input == null) {
??????????? log.error(internal.getMessage("configWebXml"));
??????????? throw new ServletException(internal.getMessage("configWebXml"));
??????? }
??????? try {
???????? ???// 解析當(dāng)前配置文件
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 {
??????????????? //
解析完畢,關(guān)閉輸入
input.close();
??????????? } catch (IOException e) {
??????????????? log.error(internal.getMessage("configWebXml"), e);
??? /**???????????
如果有異常,當(dāng)前部進行處理,而是留給他的調(diào)用者來處理。其實是當(dāng)前的調(diào)用部分沒有處理的能力。我們可以這樣理解,假設(shè)你想在出現(xiàn)了這類異常異常的地方給用戶一個提示,但是在我們封裝功能實現(xiàn)的時候,我們并不知道誰會來調(diào)用,所以我們只有把異常拋出,讓調(diào)用者自己去處理。
???
這一點也許不太好理解,不過,如果理解了,可能你就能夠靈活的使用異常了。
*/
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) ? 初始化數(shù)據(jù)源配置模塊
??????????? initModuleDataSources(moduleConfig);
(4) ? 初始化 PlugIn 模塊
??????????? initModulePlugIns(moduleConfig);
??????????? moduleConfig.freeze();
[8] ? 初始化參數(shù)
??????????? 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] ???????? 部分模塊的詳細實現(xiàn):
a. ????? 工廠的初始化如何實現(xiàn)的:
??? /**
???? * <p>Initialize the factory used to create the module configuration.</p>
???? * @since Struts 1.2
???? */
protected void initModuleConfigFactory(){
/**
這個部分的代碼就是取得參數(shù)。
這個參數(shù)你可以自己擴展你的模塊實現(xiàn)工廠。但是一般都沒有自己去做。
所以一般都使用的默認(rèn)的工廠初始化配置。
*/
??????? String configFactory = getServletConfig().getInitParameter("configFactory");
/**
下面的代碼,只有你做了自己的配置才會有效。否則一般是不執(zhí)行的。
*/
??????? if (configFactory != null) {
/**
設(shè)置此工廠,并把其參數(shù)存入到
ModuleConfigFactory.factoryClass
屬性中。
此部分可以看
ModuleConfigFactory
的代碼。
ModuleConfigFactory
是一個
*/
??????????? ModuleConfigFactory.setFactoryClass(configFactory);
??????? }
??? }
b. ????? 資源模塊式如何初始化的
//
調(diào)用的部分
protected String config = "/WEB-INF/struts-config.xml";
------------------------------------------------------------------??????????
ModuleConfig moduleConfig = initModuleConfig("", config);
initModuleMessageResources(moduleConfig);
?????? //
實現(xiàn)的部分:
??? protected void initModuleMessageResources (ModuleConfig config)
??????? throws ServletException {
??????
?????? /**
??????
在
struts-config.xml
中的資源文件配置,你可能配置了多個資源,所以此處取得是一個數(shù)組
*/
??????? 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";
就是返回的這個值,如果你沒有做其他的設(shè)置的話。
一般情況下,我們都用得是默認(rèn)的
*/
??????????? String factory = mrcs[i].getFactory();
/**
??????
此處對每一個資源配置文件都回去創(chuàng)建一個工廠
*/
??????????? 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());
?????? /**
這一部分非常重要。
我們之所以能夠直接調(diào)用,就是因為,初始化后,我們就把此
resources
放到了其對應(yīng)的當(dāng)前應(yīng)用的屬性值里面了。之后我們就可以直接調(diào)用了。
?????? */
??????????? getServletContext().setAttribute(
??????????????? mrcs[i].getKey() + config.getPrefix(),
??????????????? resources);
??????? }
??? }
c. ????? 數(shù)據(jù)模塊是如何初始化的
==========================================================
//
調(diào)用部分
initModuleDataSources(moduleConfig);
//
實現(xiàn)部分:
/**
???? * <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());
/**
因為你可能配置了多個數(shù)據(jù)源,所以此處返回的是一個數(shù)組
*/
??????? DataSourceConfig dscs[] = config.findDataSourceConfigs();
??
?//
處理沒有配置數(shù)據(jù)源的情況
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()));
??????????? }
/**
??????
這一個部分很重要。
??????
把初始化后的數(shù)據(jù)源放入到
servlet
的屬性中,所以我們才可以通過
struts
的對應(yīng)屬性直接訪問。
? protected String key = Globals.DATA_SOURCE_KEY;
所以,我們可以通過
Globals.DATA_SOURCE_KEY
屬性的值來取得其配制后的數(shù)據(jù)源。
如果多個的話,可以通過數(shù)據(jù)源的參數(shù)
ID
來配置和調(diào)用。
*/
??????????? getServletContext().setAttribute
??????????????? (dscs[i].getKey() + config.getPrefix(), ds);
???????????
dataSources.put(dscs[i].getKey(), ds);
??????? }
??????? dataSources.setFast(true);
??? }
至此,Struts系統(tǒng)初始化完畢。
?
?
|----------------------------------------------------------------------------------------|
版權(quán)聲明 版權(quán)所有 @zhyiwww
引用請注明來源 http://www.aygfsteel.com/zhyiwww
|----------------------------------------------------------------------------------------|