- 浏览: 16241 次
- 性别:
- 来自: 深圳
-
最近访客 更多访客>>
最新评论
-
harrison2010:
我了个去,继续不?
degister In Action (关于struts框架中的xml解析) part3 -
harrison2010:
javaeye 竟然跟csdn合作了
不計劃不成活 -
harrison2010:
成佛,加油加油
不計劃不成活 -
7upCat:
我这篇文章主要讲的是关于Digester的使用,而关于stru ...
degister In Action (关于struts框架中的xml解析) part3 -
iovy:
LZ,开源框架的代码不是这么看的,你这叫只见一叶,不见森林。
degister In Action (关于struts框架中的xml解析) part3
CH4. 分析 Struts中的struts-config.xml解析过程
写在最前面:说实在的,这部分会有点难懂,我自己也觉得很困难来把它整个说清楚,涉及到的类和方法都太宠杂,只能尽力而为.
因为本文主要是讨论使用digester进行xml解析.所以不关注,整个ActionServlet 初始化的整个流程,我们把注意力集中在解析xml配置文件的那部分代码,但读者还是要对Servlet,和Struts的一些相关的知识有一定的了解,比如说Servlet的生命周期,Struts的配置文件中的元素组成结构以及各个标签的含意是什么.
4.1 introduction of ActionServlet
形象点说,ActionServlet是Struts世界中的接线员,负责接收所有的请求,并把这个请求,转发给合适的人(这里的人在Struts中就是Action类型的实例了.
ActionServlet继承了,javax.servlet.http.HttpServlet.是个Servlet当然也就遵循Servlet的生命周期.
我们这里复习一下Servlet的生命周期
1.Servlet实例被创建.
2. 调用init(ServletConfig config )方法.(在HttpServlet中实际上在init(ServletConfig config ) 中调用了init()所以我们可以覆盖 init()方法来进行初例化)
3.接受客户请求.调用service方法.(在HttpServelt中,会调用doGet和doPost)
4. 调用destroy()方法.
5.实例被销毁.
接着,我们看一下,ActionServlet在生命周期都做了些什么事情呢?
init()方法
在struts源码中我增加了相关的注释,并删除了异常处理的代码,希望大家能更容易理解^^
public void init() throws ServletException { //初使化国际化相关的,MessageResource bundle initInternal(); //初使化我们这个controller servlet的字符转换函数 initOther(); //初使化web.xml中的信息. initServlet(); //将ActionServlet实例以Globals.ACTION_SERVLET_KEY为key存在ServletContext对象中 getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this); initModuleConfigFactory(); // Initialize modules as needed //初使化,ModuleConfig这个moduleConfig相当重要,封装了所有的,struts-config.xml中的信息. //也就是我们解析struts-config.xml中的root元素了.一会我们将来看一下initModuleConfig中都做了些什么事情. ModuleConfig moduleConfig = initModuleConfig("", config); //通过moduleConfig中的配置文件信息,创建MessageResource对象. initModuleMessageResources(moduleConfig); //通过moduleConfig中的配置文件信息,创建DataSource对象. initModuleDataSources(moduleConfig); //通过moduleConfig中的配置文件信息,创建 initModulePlugIns(moduleConfig); //将配置文件中的各个对象,设置成已配置状态. moduleConfig.freeze(); Enumeration names = getServletConfig().getInitParameterNames(); //通过web.xml的中参数配置,得到其它的Struts的配置文件并以上面的方式对,moduleConfig进行同样的配置 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(); }
由上面的代码可以看出,在init方法中,Struts对很的信息进行了初使化,并使用,
ModuleConfig moduleConfig = initModuleConfig("", config)方法得到了struts-config.xml中的信息,所以解析配置文件的具体的方法也就是在这个方法里面完成的了.我们将在一会详细讲解一下这个方法的代码.
doGet 以及 doPost方法.
将请求委托给
process(request, response);方法.
我们再来看一下process方法又做了些什么呢?
protected void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { ModuleUtils.getInstance().selectModule(request, getServletContext()); ModuleConfig config = getModuleConfig(request); //通过config对象来得来一个RequestProcessor对象(第一次请求的时候,为空的,). RequestProcessor processor = getProcessorForModule(config); if (processor == null) { //如果还没有配置一个RequestProcessor对象,就会通过,config对象来生成一个,默认就为org.apache.struts.action.RequestProcessor可以被扩展. processor = getRequestProcessor(config); } /** 通过processor来转发处理请求.(无非是通过请求的路径,以及config对象来生成 ActionMapping BeanForm 以及,具体的Action实例,和 ActionForward) 然后调用得到的Action bean的execute方法 */ processor.process(request, response); }
所有的请求最终都是通过,ActionServelt 的process方法中被RequestProcessor来处理的,
RequestProcessor通过ModuleConfig对象里的信息,以前客户端的请求的路径,分别得到,在配置文件中所配置的,Action bean的实例, ActionMapping的信息,ActionForward的信息,以及,可以所配置的FormBean的信息.然后调用 Action bean 实例的execute方法来完成整个请求.
最后再来看destory方法
public void destroy() { /** * 和 init()方 法 相 对 应 ,做 了 相 关 的 清 理 工 作 ,具 体 的 ,读 者 可 以 参 见 init()方 法 */ if (log.isDebugEnabled()) { log.debug(internal.getMessage("finalizing")); } destroyModules(); destroyInternal(); getServletContext().removeAttribute(Globals.ACTION_SERVLET_KEY); // Release our LogFactory and Log instances (if any) ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { classLoader = ActionServlet.class.getClassLoader(); } LogFactory.release(classLoader); PropertyUtils.clearDescriptors(); }
这一节,我们详细的介绍了ActionServlet的生命周期中各个阶段所做的事情.下一节,我们将专注于,initModuleConfig方法,看一下struts只解析xml文件的具体过程.
4.2 concentrate on the method of initModuleConfig
上一节,我们讲了ActionServlet的生命周期,其中有一个方法进入了我们的视野.
ModuleConfig moduleConfig = initModuleConfig("", config) ,在这一节中我们将要仔细分析这个方法的源代码,
当然为了更容易理解,我将删除掉struts中源码的一部分,只保留核心那部分代码..
protected ModuleConfig initModuleConfig(String prefix, String paths) throws ServletException { // Parse the configuration for this module ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory(); /** 通过prefix的值来创建ModuleConfig对象 这里的prefix的含意是,模块名称,使用过struts的朋友可能有这个印象,在struts中,如果配置多个配置文件,是要在. web.xml中指定的路径是 config/name/***.xml 这里的name就是prefix了.^^ <init-param> <param-name>config/name</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> 如这个web.xml中的配置中的, name/即为模块的prefix */ ModuleConfig config = factoryObject.createModuleConfig(prefix); // Configure the Digester instance we will use //初使化并,得到Digester对象(在初使化的过程中一定会添加各种监听,我们一会将看一下初使化的具体代码) 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 = paths.trim(); paths = ""; } if (path.length() < 1) { break; } //将 解 析 的 具 体 操 作 委 托 给 parseModuleConfigFile方 法 this.parseModuleConfigFile(digester, path); } //将 所 得 到 的 ModuleConfig对 象 以 org.apache.struts.action.MODULE为 key放 进 ServletContext对 象 中 去 //以 方 便 以 后 的 使 用 getServletContext().setAttribute( Globals.MODULE_KEY + config.getPrefix(), config); return config; }
整个方法中很明确,首先,通过,initConfigDigester();方法来得到一个,已经被设置了各种监听的Digester对象,然后将path路径下的xml 文件进行解析.那么,到底设置了哪些监听规则呢?我们来跟到initConfigDigester()方法中看一下.
(源码的版本依然被我阉割了,以便于大家理解.)
protected Digester initConfigDigester() throws ServletException { //是否已经存在解析好了的configDigester对象了,如果是直接返回. if (configDigester != null) { return (configDigester); } // Create a new Digester instance with standard capabilities //创建一个新的Digester对象,并设置参数 configDigester = new Digester(); //名字是否空间敏感. configDigester.setNamespaceAware(true); //设置是否验证XML文档有效 configDigester.setValidating(this.isValidating()); //设置是否使用上下文的ClassLoader(通过,Thread.currentThread().getContextClassLoader()得到的)来加载 //为digester对象设置的监听类 configDigester.setUseContextClassLoader(true); //为digester对象来填加监听类集合 configDigester.addRuleSet(new ConfigRuleSet()); // Return the completely configured Digester instance return (configDigester); }
从这个方法中,我们可以看到,具体的匹配规则是通过,一个叫ConfigRuleSet()的对象传进来的.
我们接着考查,到底这个ConfigRuleSet()是个啥鬼东西^^.
这个类大约有五百行大小,为了方便,我们在这里讲解,我们只截取其中的一部分,但这也足够大家理解了.
public class ConfigRuleSet extends RuleSetBase { public void addRuleInstances(Digester digester) { //步骤一 digester.addRule ("struts-config/action-mappings", new SetActionMappingClassRule()); //步骤二 digester.addFactoryCreate ("struts-config/action-mappings/action", new ActionMappingFactory()); //步骤三 digester.addSetProperties ("struts-config/action-mappings/action"); //步骤四 digester.addSetNext ("struts-config/action-mappings/action", "addActionConfig", "org.apache.struts.config.ActionConfig"); //步骤五 digester.addSetProperty ("struts-config/action-mappings/action/set-property", "property", "value"); } final class SetActionMappingClassRule extends Rule { public SetActionMappingClassRule() { super(); } public void begin(String namespace, String name, Attributes attributes) throws Exception { String className = attributes.getValue("type"); if (className != null) { ModuleConfig mc = (ModuleConfig) digester.peek(); mc.setActionMappingClass(className); } } } final class ActionMappingFactory extends AbstractObjectCreationFactory { public Object createObject(Attributes attributes) { // Identify the name of the class to instantiate String className = attributes.getValue("className"); if (className == null) { ModuleConfig mc = (ModuleConfig) digester.peek(); className = mc.getActionMappingClass(); } // Instantiate the new object and return it Object actionMapping = null; try { actionMapping = RequestUtils.applicationInstance(className); } catch (Exception e) { digester.getLogger().error( "ActionMappingFactory.createObject: ", e); } return actionMapping; } } }
下面我们就按照代码中注释的五个步骤一步一步分析.
步骤一. digester.addRule
("struts-config/action-mappings",
new SetActionMappingClassRule());
当解析的时候碰到<action-mappings>标签时,调用下面的方法
public void begin(String namespace, String name, Attributes attributes) throws Exception { String className = attributes.getValue("type"); if (className != null) { ModuleConfig mc = (ModuleConfig) digester.peek(); mc.setActionMappingClass(className); } }我们看到它将取得<action-mappings >
标签中的type元素的值并把它设置给配置文件的Root元素ModuleConfig的actionMappingClass,这个域的值默认为
org.apache.struts.action.ActionMapping
步骤二, digester.addFactoryCreate
("struts-config/action-mappings/action",
new ActionMappingFactory());
当遇到<action>标签时,将使用ActionMappingFactory类的createObject方法来创建一个对象.
public Object createObject(Attributes attributes) { // Identify the name of the class to instantiate String className = attributes.getValue("className"); if (className == null) { ModuleConfig mc = (ModuleConfig) digester.peek(); className = mc.getActionMappingClass(); } // Instantiate the new object and return it Object actionMapping = null; try { actionMapping = RequestUtils.applicationInstance(className); } catch (Exception e) { digester.getLogger().error( "ActionMappingFactory.createObject: ", e); } return actionMapping; }
通过,<action > 标签中的className属性来创建对象,当这个className没有指定时,使用默认的
org.apache.struts.action.ActionMapping类来创建对象.
步骤三. digester.addSetProperties
("struts-config/action-mappings/action");
当碰到<action>标签时,使用<action >标签中的属性来设置 ActionMapping对象.
主要包括path, type,scope,validate等 这样我们就可以看到,所有的关于bean的配置信息实际都是放在了
ActionMapping对象中了.
步骤四. digester.addSetNext
("struts-config/action-mappings/action",
"addActionConfig",
"org.apache.struts.config.ActionConfig");
我们知道,整个xml文件的解析的项层对象是一个ModuleConfig对象,那么上面的这个方法的意思就是说,
当碰到<action>标签的时候,我们把生成 的ActionMapping对象,通过调用ModuleConfig对象的addActionConfig方法设置给root对象.
看一下,addActionConfig方法的具体实现.
public void addActionConfig(ActionConfig config) { if (configured) { throw new IllegalStateException("Configuration is frozen"); } config.setModuleConfig(this); //通过ActionMapping中的path为key,以ActionMapping对象为值放入actionConfigs这个Map中 actionConfigs.put(config.getPath(), config); actionConfigList.add(config); }
步骤五 digester.addSetProperty
("struts-config/action-mappings/action/set-property",
"property", "value");
}
要使用action-mappings/action/set-property,需要编写ActionMapping子类,并给action-mappings 标签加上type属性,属性值就是我们编写的字类。这样当action的execute享有客户操作时将得到我们编写的ActionMapping事例。
我们编写的ActionMapping要具有action-mappings/action/set-property所设置的所有属性。如果action-mappings/action拥有set-property子标签,那么execute方法获得的ActionMapping事例就拥有set-property所设置的属性值。
一般来讲我们都不会自己来扩展ActionMapping类,也就使得这个方法不是特别重要.
4.3 小节
通过上一节,我们分析了ActionMapping的解析过程,当然在struts配置文件中,其它部分的解析方式实际上都是同这个类似的,大家完全可以举一反三的去看它的源代码.(重复性劳动没有啥意义SO.)
评论
3 楼
harrison2010
2012-05-15
我了个去,继续不?
2 楼
7upCat
2009-02-22
我这篇文章主要讲的是关于Digester的使用,而关于struts源码分析部分,只是用来示例Digester实际应用中是如何使用的。所以,你别指望我根据这个来把Struts讲的很清楚,Digester是Struts用来解析xml文件的一个包。。
为什么看开源框架源码?
1. 成功的开源框架的共同待性:体现了某种先进的思想,并给出了一个比较高质量的实现。
而我们主要是要先明白思想。
看,STRUTS, 关注它是如何实现的MVC分离。
看,SPRING,我们要明白,AOP,IOC。
2.成功的开源框架,住住都有比较好的代码习惯(包含命名,注释,类的责任划分)。这点值得我们学习的。
3.成功的开源框架,一般都使用了大量的设计模式,这也是你学习设计模式的一种实战的教科书。
4.做为程序员,是应该有点探取精神的,我们做程序员,不是做代码搬运工人,你应该对你使用的框架有一定的了解,并能根据你的业务需要对它进行定制 。
为什么看开源框架源码?
1. 成功的开源框架的共同待性:体现了某种先进的思想,并给出了一个比较高质量的实现。
而我们主要是要先明白思想。
看,STRUTS, 关注它是如何实现的MVC分离。
看,SPRING,我们要明白,AOP,IOC。
2.成功的开源框架,住住都有比较好的代码习惯(包含命名,注释,类的责任划分)。这点值得我们学习的。
3.成功的开源框架,一般都使用了大量的设计模式,这也是你学习设计模式的一种实战的教科书。
4.做为程序员,是应该有点探取精神的,我们做程序员,不是做代码搬运工人,你应该对你使用的框架有一定的了解,并能根据你的业务需要对它进行定制 。
1 楼
iovy
2009-02-22
LZ,开源框架的代码不是这么看的,你这叫只见一叶,不见森林。
相关推荐
### 精通Struts:基于MVC (Part 3) #### Struts框架概述 Struts是一个开源的Java Web应用程序框架,它遵循Model-View-Controller(MVC)设计模式。MVC是一种软件架构模式,它将应用程序分为三个主要部分:模型、...
本文将围绕标题“精通Struts:基于MVC (part 2)”进行展开,并结合描述中的内容:“这是一本关于Struts很好的书,书中全面地介绍了Struts框架在J2EE中的完美运用...”,来生成相关的知识点。 ### Struts框架简介 ...
2. **请求被ActionServlet接收**:ActionServlet是Struts框架的核心控制器,它根据配置文件struts-config.xml中的映射找到对应的Action。 3. **执行Action**:Action是具体处理用户请求的类,它负责调用业务逻辑层的...
3. ActionServlet根据配置文件struts-config.xml中的映射关系找到对应的Action。 4. ActionServlet创建一个ActionForm对象,并将请求参数填充到ActionForm中。 5. ActionServlet将ActionForm对象传递给Action对象...
Result类型是通过配置在Action类的execute方法返回值或者struts.xml配置文件中定义的。默认情况下,如果未明确指定Result类型,那么Struts2会默认使用"dispatcher",它将请求分发到一个JSP页面。然而,Struts2提供了...
Struts框架使用struts-config.xml文件进行配置,这个文件定义了Action的映射、Form Bean的声明等重要的配置信息。例如,可以配置Action的路径、方法名等。 ```xml <action path="/welcome" type=...
在struts.xml配置文件中,你可以为每个Action配置不同的Result,指定不同情况下应返回的视图。 3. **OGNL(Object-Graph Navigation Language)**:OGNL是Struts2中用于数据绑定和表达式语言,它允许在Action与视图...
在"struts2 apps part2"这个主题中,我们将会深入探讨Struts2框架的更多特性和应用,以及如何利用它来开发更复杂的web应用程序。 1. **Struts2框架概述**: Struts2是基于MVC(Model-View-Controller)设计模式的...
本实例源码集是“Struts开发入门与项目实践part2”的配套资源,旨在帮助初学者通过实际操作掌握Struts框架的核心概念和使用技巧。 在Struts框架中,核心概念包括: 1. **Action类**:Action类是业务逻辑的载体,...
Struts2是Java EE开发中的一个非常重要的框架,它主要用于构建Web应用程序,尤其在企业级应用中广泛应用。作为轻量级的解决方案,Struts2提供了一种组织良好、可扩展的架构,帮助开发者处理控制器逻辑、视图呈现以及...
通过这些示例,开发者可以学习到如何配置Struts 2的XML配置文件(struts.xml),创建Action类,定义视图页面,以及如何利用拦截器进行业务逻辑处理。 需要注意的是,由于文件大小限制,此压缩包被分为两部分上传,...
总之,"struts-2.3.8-all-part1"包含了Struts 2框架的完整构建,对于开发者来说是一个宝贵的资源,无论是初学者还是经验丰富的开发者,都能从中学习到很多关于MVC架构、Web开发最佳实践以及如何有效利用框架提升开发...
在Struts2框架中,核心组件包括Action类、配置文件(struts.xml)、拦截器(Interceptors)以及结果类型(Result)。Action类是业务逻辑的载体,用户请求会映射到特定的Action,然后执行相应的业务逻辑。配置文件...
在配置文件(struts.xml)中,我们需要为这两个Action定义对应的映射: ```xml <struts> <package name="default" namespace="/" extends="struts-default"> <action name="upload" class=...
总的来说,Struts 2.3.1.2-part2.rar这个压缩包包含了SSH框架中Struts 2的升级版本,其文档和源代码对于开发者来说是宝贵的资源,可以帮助他们更好地掌握SSH框架的使用,提高开发效率,构建高效、稳定的企业级Web...
5. **配置文件**:通常为struts.xml,用于定义Action、结果类型、拦截器栈等,是整个框架的配置中心。 6. **表达式语言(OGNL)**:Struts2使用OGNL作为默认的表达式语言,允许在Action、视图和配置文件中方便地...
在“轻量级应用Java EE企业实战”系列中,"struts2.part2"这部分可能涉及了更深入的Struts2使用技巧,如自定义拦截器的实现、Action的分层设计、动态结果集的配置以及与Ajax的集成等内容。学习这部分内容将有助于...
Struts通过使用Servlet API中的`Part`接口(在Servlet 3.0及以上版本中引入)或者`HttpServletRequest`的`getParts()`方法来处理文件上传。它依赖于第三方库如Apache Commons FileUpload,这个库提供了处理多部分...
"Struts2-part01"可能包含的是该系列学习的第一部分内容,可能涵盖了Struts2的基础概念、环境搭建、Action的创建和执行、OGNL的基本使用等内容。通过学习这部分代码,开发者能够初步掌握Struts2的基本操作和工作原理...