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://m.tkk7.com/zhyiwww
|----------------------------------------------------------------------------------------|
posted on 2006-12-25 16:47
zhyiwww 閱讀(3354)
評論(1) 編輯 收藏 所屬分類:
j2ee