struts1之ActionServlet詳解_動力節(jié)點(diǎn)Java學(xué)院整理
在web.xml中我們除了配置ActionServlet還配置了一些初始化參數(shù)信息,首先我們看第一個config參數(shù),這里配置的是/WEB-INF/struts-config.xml,因?yàn)橐旅鎮(zhèn)鬟f一個這樣一個配置信息,這個xml文件名是struts1標(biāo)準(zhǔn)的名字,所以這里這個初始化信息完全可以刪除,如果不用這個標(biāo)準(zhǔn)名稱這里就必須要在這里配置?,F(xiàn)在我們配置的是標(biāo)準(zhǔn)名字,所以我們可以刪除,這是為什么呢?這里要看ActionServlet源代碼才可以。

從圖片上我們能看到ActionServlet中已經(jīng)寫好了默認(rèn)的config信息了,就是標(biāo)準(zhǔn)名字。所以這里刪除也是可以的。
在看下面的debug和detail參數(shù),這兩個參數(shù)信息是有關(guān)日志信息級別的設(shè)置,主要關(guān)于解析配置文件/WEB-INF/struts-config.xml級別的初始化參數(shù)。這里這兩個參數(shù)可以完全去掉也不影響。
最后還有一個load-on-startup配置,這個是初始化servlet級別的初始化信息,這個參數(shù)如果大于等于0就是說明在服務(wù)器一啟動就把servlet初始化,也就是調(diào)用ActionServlet的init方法,這個也可以到ActionServlet的源代碼中去查找。
當(dāng)ActionServlet初始化的時候就會讀取/WEB-INF/struts-config.xml信息到內(nèi)存中,讀到內(nèi)存是以什么樣的形式展現(xiàn)的呢?我們現(xiàn)在可以看一下以前博客的那個mvc實(shí)例,那里面讀取配置文件中的信息是以Actionmapping的形式展現(xiàn)的。另外servlet-mapping的配置就不講解了,這個都知道就是匹配url路徑的,當(dāng)遇到url-pattern的路徑時候就會實(shí)例化Actionservlet。
通過這篇文章我們知道了當(dāng)我們請求的時候ActionServlet是怎樣實(shí)例化的,也知道為什么我們要配置web.xml信息了。那么我們?yōu)槭裁匆渲?WEB-INF/struts-config.xml文件,ActionServlet是如何傳遞請求的,如何和ActionForm、ActionMapping、Action等交互的最終完成用戶請求的呢?
我們先從ActionServlet源代碼的init方法開始。因?yàn)锳ctionServlet就是一個Servlet,它也是具有典型的那幾個方法init、doget、dopost等方法。既然是初始化,那么我們就要看init方法。Init方法的源代碼如下:
/**
* <p>Initialize this servlet. Most of the processing has been factored into
* support methods so that you can overrideparticular functionality at a
* fairly granular level.</p>
*
* @exception ServletException if we cannotconfigure ourselves correctly
*/
publicvoidinit() throwsServletException {
// Wraps the entire initialization in a try/catch tobetter handle
// unexpected exceptions and errors to provide better feedback
// to the developer
try {
initInternal();
initOther();
initServlet();
getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
initModuleConfigFactory();
// Initialize modules as needed
ModuleConfig moduleConfig =initModuleConfig("", config);
initModuleMessageResources(moduleConfig);
initModuleDataSources(moduleConfig);
initModulePlugIns(moduleConfig);
moduleConfig.freeze();
Enumeration names =getServletConfig().getInitParameterNames();
while (names.hasMoreElements()) {
String name = (String)namesnextElement();
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());
thisdestroyConfigDigester();
} 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
logerror("Unable to initialize Struts ActionServlet due to an "
+ "unexpected exception or error thrown, so marking the "
+ "servlet as unavailable. Mostlikely, this is due to an "
+ "incorrect or missing library dependency.", t);
throw new UnavailableException(t.getMessage());
}
}
在解釋這段代碼的流程和意思之前,有必要說一句,就是當(dāng)我們在eclipse里面看代碼的時候,尤其是看一段生疏的很長的代碼的時候,希望能夠經(jīng)常使用Ctrl鍵(多余的不解釋)。
下面開始講解這段代碼的流程和具體每一步的含義,如果有不正確的地方,希望指正。
首先映入眼簾的是initInternal()方法。這個方法的實(shí)現(xiàn)代碼是:
代碼段一:
/**
* <p>Initialize our internal MessageResourcesbundle</p>
*
* @exception ServletException if we cannotinitialize these resources
*/
protectedvoidinitInternal() throwsServletException {
// :FIXME: Document UnavailableException
try {
internal = MessageResourcesgetMessageResources(internalName);
} catch (MissingResourceException e) {
log.error("Cannot load internal resources from '"+ internalName+ "'",
e);
throw new UnavailableException
("Cannot load internal resources from '"+ internalName+ "'");
}
}
代碼段二:
/**
* Create and return an instance of <code>MessageResources</code> for the
* created by the default <code>MessageResourcesFactory</code>.
*
* @param config Configuration parameterfor this message bundle.
*/
publicsynchronizedstaticMessageResources getMessageResources(String config) {
if (defaultFactory == null) {
defaultFactory =MessageResourcesFactory.createFactory();
}
return defaultFactory.createResources(config);
}
代碼段三:
/**
* Create and return a <code>MessageResourcesFactory</code> instance ofthe
* appropriate class, which can be used tocreate customized
* <code>MessageResources</code>instances If no such factory can be
* created, return <code>null</code> instead
*/
publicstaticMessageResourcesFactory createFactory(){
// Construct a new instance of the specified factory class
try {
if (clazz == null)
clazz = RequestUtils.applicationClass(factoryClass);
MessageResourcesFactory factory =
(MessageResourcesFactory) clazz.newInstance();
return (factory);
} catch (Throwable t) {
LOG.error("MessageResourcesFactory.createFactory",t);
return (null);
}
}
這個方法的具體作用就是初始化MessageResources,具體實(shí)現(xiàn)是工廠模式,首先判斷defaultFactory是否存在,不存在則創(chuàng)建工廠,defaultFactory = MessageResourcesFactory.createFactory(),在通過工廠創(chuàng)建資源類defaultFactory.createResources(config);存在則直接創(chuàng)建資源類。
initOther()的方法,主要是初始化其它的配置,獲取我們自己的struts-config配置文件的路徑,而它的默認(rèn)路徑就是web-inf/struts-config.xml,另外這個方法還會注冊一些轉(zhuǎn)換類的。具體源代碼是:
/**
* <p>Initialize other global characteristics ofthe controller servlet</p>
*
* @exception ServletException if we cannotinitialize these resources
*/
protectedvoidinitOther() throwsServletException {
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 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);
}
}
initServlet()方法是利用digester讀取web.xml文件并且放到servletContext中。具體實(shí)現(xiàn)源代碼:
/**
* <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
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()) {
logdebug("Mapping for servlet '" + servletName + "' = '" +
servletMapping + "'");
}
if (servletMapping != null) {
getServletContext().setAttribute(Globals.SERVLET_KEY, servletMapping);
}
}
首先說在說之前還是先講init方法的具體實(shí)現(xiàn)代碼寫出來以便大家方便閱讀和理解。
Init源代碼:
public void init() throws ServletException {
try {
//初始化資源類
initInternal();
//注冊轉(zhuǎn)換類
initOther();
//利用digester讀取webxml文件并且將其放到servletContext中
initServlet();
getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
initModuleConfigFactory();
ModuleConfig moduleConfig = initModuleConfig("", config);
initModuleMessageResources(moduleConfig);
initModuleDataSources(moduleConfig);
initModulePlugIns(moduleConfig);
moduleConfig.freeze();
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) {
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());
}
}
getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY,this);這句話是將ActionServlet實(shí)例將以Globals.ACTION_SERVLET_KEY作為key存入servletcontext中。
這里的Globals.ACTION_SERVLET_KEY在ActionServlet已經(jīng)給出了聲明:
public static final String ACTION_SERVLET_KEY= "org.apache.struts.action.ACTION_SERVLET";
接下來initModuleConfigFactory()方法,這個方法主要的作用是解析在web.xml中configFactory的text值。如果configFactory有配置,則將設(shè)置ModuleConfigFactory中得factoryClass值,否則默認(rèn)得為efaultModuleConfigFactory。該方法其實(shí)宗旨是讓開發(fā)人員自己開發(fā)出ModuleConfigFactory,從而得到自己所需要的ModuleConfig類。因?yàn)槲覀兊膶?shí)例中沒有配置這個參數(shù)信息,所以我們這里的實(shí)例是要defalutModelConfigFactory了。
代碼段一:
protected voidinitModuleConfigFactory(){
String configFactory =getServletConfig().getInitParameter("configFactory");
if (configFactory != null) {
ModuleConfigFactory.setFactoryClass(configFactory);
}
}
代碼段二:
public static void setFactoryClass(String factoryClass) {
ModuleConfigFactory.factoryClass = factoryClass;
ModuleConfigFactory.clazz = null;
}
代碼段三:
protected static String factoryClass =
"org.apache.struts.config.impl.DefaultModuleConfigFactory";
}
ModuleConfig moduleConfig =initModuleConfig("", config)方法是非常重要的,initModuleConfig方法給strits-config里面的屬性初始化后放入moduleConfig對象里面去,放到moduleConfig對象里面去便于以后操作更快,因?yàn)樗俏募鳌?/p>
具體實(shí)現(xiàn)代碼:
protected ModuleConfig initModuleConfig(Stringprefix, String paths)
throws ServletException {
// :FIXME: Document UnavailableException? (Doesn't actually throw anything)
if (log.isDebugEnabled()) {
log.debug(
"Initializing module path '"
+ prefix
+ "' configuration from '"
+ paths
+ "'");
}
// Parse the configuration for this module
ModuleConfigFactory factoryObject= ModuleConfigFactory.createFactory();
ModuleConfig config =factoryObject.createModuleConfig(prefix);
// Configure the Digester instance we will use
Digester digester =initConfigDigester();
// Process each specified resource path
while (paths.length() > 0) {
digester.push(config);
String path = null;
int comma = paths.indexOf(',');
if (comma >= 0) {
path =paths.substring(0, comma).trim();
paths =paths.substring(comma + 1);
} else {
path = pathstrim();
paths = "";
}
if (pathlength() < 1){
break;
}
this.parseModuleConfigFile(digester,path);
}
getServletContext().setAttribute(
Globals.MODULE_KEY +config.getPrefix(),
config);
// Force creation and registration of DynaActionFormClass instances
// for all dynamic form beans we wil be using
FormBeanConfig fbs[] =config.findFormBeanConfigs();
for (int i = 0; i < fbs.length; i++) {
if (fbs[i].getDynamic()) {
fbs[i].getDynaActionFormClass();
}
}
return config;
}
這里有必要解析一下這段代碼。首先得到繼承ModuleConfigFactory的實(shí)現(xiàn)類,如果在initModuleConfigFactory()中能設(shè)置factoryClass屬性,則能生成客戶化得factory,否則得到得是默認(rèn)得DefaultModuleConfigFactory類,該工廠得到ModuleConfigImpl類。然后調(diào)用initConfigDigester()該方法為解析配置文件做準(zhǔn)備,初始化Digest類(具體digest的初始化實(shí)現(xiàn)就不講解)。最后返回ModuleConfig,而這時的ModuleConfig里面封裝了所有的struts-config.xml中的信息。
最后的幾個方法就簡單說一下就行,不是非常難理解:
initModuleMessageResources(moduleConfig)方法是通過moduleConfig中的配置文件信息,創(chuàng)建MessageResource對象.
initModuleDataSources(moduleConfig)方法是通過moduleConfig中的配置文件信息,創(chuàng)建DataSource對象. initModulePlugIns(moduleConfig)加載并初始化默認(rèn)應(yīng)用模塊的所有插件的。
moduleConfig.freeze()是將配置文件中的各個對象,設(shè)置成已配置狀態(tài).
最后我們看到了,下面還有一段同上面代碼的循環(huán)代碼,這段代碼的主要意思就是當(dāng)默認(rèn)子應(yīng)用模塊被成功初始化后,如果應(yīng)用還包括其他子應(yīng)用模塊,將重復(fù)流程,分別對其他子應(yīng)用模塊進(jìn)行初始化。這個也是很好理解的。
到此為止ActionServlet就init完成。
- Java框架Struts2實(shí)現(xiàn)圖片上傳功能
- Java框架學(xué)習(xí)Struts2復(fù)選框?qū)嵗a
- struts2標(biāo)簽總結(jié)_動力節(jié)點(diǎn)Java學(xué)院整理
- struts1之簡單mvc示例_動力節(jié)點(diǎn)Java學(xué)院整理
- Struts1之url截取_動力節(jié)點(diǎn)Java學(xué)院整理
- Struts1教程之ActionMapping_動力節(jié)點(diǎn)Java學(xué)院整理
- java struts2框架簡介
- Java struts2 package元素配置及實(shí)例解析
相關(guān)文章
java使用Jdom實(shí)現(xiàn)xml文件寫入操作實(shí)例
這篇文章主要介紹了java使用Jdom實(shí)現(xiàn)xml文件寫入操作的方法,以完整實(shí)例形式分析了Jdom針對XML文件寫入操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
SpringBoot + Shiro前后端分離權(quán)限
這篇文章主要為大家詳細(xì)介紹了SpringBoot + Shiro前后端分離權(quán)限,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
MyBatis-Plus實(shí)現(xiàn)多數(shù)據(jù)源的示例代碼
這篇文章主要介紹了MyBatis-Plus實(shí)現(xiàn)多數(shù)據(jù)源的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Hibernate雙向一對一映射關(guān)系配置代碼實(shí)例
這篇文章主要介紹了Hibernate雙向一對一映射關(guān)系配置代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
十大常見Java String問題_動力節(jié)點(diǎn)Java學(xué)院整理
本文介紹Java中關(guān)于String最常見的10個問題,需要的朋友參考下吧2017-04-04

