首页 Struts源码解析

Struts源码解析

举报
开通vip

Struts源码解析Struts 源码深度解析 1.​ 服务器启动,加载Web.xml文件。该配置告诉我们所有*.do的客户端请求将由ActionServlet类来处理,所以我们着重研究ActionServlet类。 action org.apache.struts.action.ActionServlet config /WEB-INF/struts-config.xml debug 2 2 action *.do ActionServlet是个典型得Servlet类,所以它有几个Servlet典型方法,init()...

Struts源码解析
Struts 源码深度解析 1.​ 服务器启动,加载Web.xml文件。该配置告诉我们所有*.do的客户端请求将由ActionServlet类来处理,所以我们着重研究ActionServlet类。 action org.apache.struts.action.ActionServlet config /WEB-INF/struts-config.xml debug 2 2 action *.do ActionServlet是个典型得Servlet类,所以它有几个Servlet典型方法,init(),destroy(),doGet(),doPost()方法。而init()方法是一个初始方法,在ActionServlet类doGet(),doPost ()方法执行之前,将调用init()方法。如下图所示。 initInternal()方法 中internal=MessageResources.getMessageResources(internalName); 初始化MessageResources 实现原理是工厂模式,首先得到一个工厂MessageResourcesFactory defaultFactory = MessageResourcesFactory.createFactory()该方法得到PropertyMessageResourcesFactory工厂类,该工厂类的createResources() PropertyMessageResources messageResources = new PropertyMessageResources(this, config, this.returnNull); String mode = null; if (getConfig() != null) { mode = getConfig().getProperty("mode"); } messageResources.setMode(mode); return messageResources; 将factory类 和config=”org.apache.struts.action.ActionResources”到PropertyMessageResources中。 initOther()方法主要功能是如果在web.xml 读取struts-config.xml文件具体位置。 和register一些转化器initServlet()方法主要功能是利用Digester对web.xml解析然后调用addServletMapping 方法将servlet-name元素的text和url-pattern的text读出来作为addServletMapping的参数传进去,并将url-pattern 赋给ActionServlet属性servletMapping,并将servletMapping存到servletContext中 initChain()方法主要功能是解析在web.xml中chainConfig的text值,如果没有chainConfig配置,则读取默认的配置文件chain-config.xml,该配置文件是在struts1.3版本新增对Http请求的处理方式配置文件,在后续的文字会详细介绍到。 initModuleConfigFactory()方法主要功能是解析在web.xml中configFactory的text值。如果configFactory有配置,则将设置ModuleConfigFactory中得factoryClass值,否则默认得为DefaultModuleConfigFactory。该方法其实宗旨是让开发人员自己开发出ModuleConfigFactory,从而得到自己所需要的ModuleConfig类。 ModuleConfig moduleConfig = initModuleConfig("", config);方法主要功能是解析struts-config.xml。首先,得到继承ModuleConfigFactory的实现类,如果在initModuleConfigFactory()中能设置factoryClass属性,则能生成客户化得factory,否则得到得是默认得DefaultModuleConfigFactory类,该工厂得到 ModuleConfigImpl 类。然后调用initConfigDigester()该方法为解析配置文件做准备,初始化Digest类 主要有设置nameSpace,validating,rule,dtd等。其中configDigester.addRuleSet(new ConfigRuleSet());中的ConfigRuleSet()是为了解析配置文件得规则类,在addRuleSet()方法中将调用ConfigRuleSet规则类的addRuleInstances()方法。该方法为解析xml添加所需要的继承了Rule接口的类到digester中 。 1.digester.addRule("struts-config/action-mappings",new SetActionMappingClassRule());中得SetActionMappingClassRule()类查看action-mappings 元素是否有type属性,如有则set到ModuleConfigImpl中的actionMappingClass. 2.digester.addFactoryCreate("struts-config/action-mappings/action", new ActionMappingFactory(cl))的ActionMappingFactory()工厂类查看action元素是否有className 属性,如果有则根据这个className的Value值创建类,否则从ModuleConfigImpl中得到actionMappingClass属性值来创建类,默认得创建ActionMapping类。 3.digester.addSetProperties("struts-config/action-mappings/action");方法将new SetPropertiesRule()这个Rule类加入到Digest中,而SetPropertiesRule类主要作用是将action元素中得属性值set到ActionMapping对应的属性中去。如 中得input的Value就set到ActionMapping中的input属性中去,其他得依次类推。 4.digester.addSetNext("struts-config/action-mappings/action", "addActionConfig","org.apache.struts.config.ActionConfig");方法的主要功能是将调用digester类push第一个push进的那个类的addActionConfig方法,并有参数为ActionConfig类型 为在这里这个类是ModuleConfigImpl,同时传进去参数为ActionMapping类 5.digester.addRule("struts-config/action-mappings/action/set-property", new BaseConfigSetPropertyRule());而BaseConfigSetPropertyRule类主要作用是如果action元素下有子元素set-property并且没有拥有属性Key 则将set-property元素的属性 property =”XXX”中的XXX为ActionMapping类的属性,Value=”YYYY”为XXX得Value值 set进ActionMapping中。如果拥有Key属性的话则存到Properties中去。 6.digester.addObjectCreate("struts-config/action-mappings/action/exception","org.apache.struts.config.ExceptionConfig", "className");方法主要功能是在元素action中有子元素exception,并以元素exception得属性className中的valueXXXX值为基础生成XXXX类,如果className属性值为空,则默认生ExceptionConfig类。 我们再回到调用ConfigRuleSet类addRuleInstances()方法的得initConfigDigester()方法,接下来是configDigester.register(registrations[i], url.toString())方法,该方法将关于struts-config.xml得DTD文件set到Digester中得entityValidator属性中去。以便以后解析配置文件的时候对文件有效性进行校验。 在addRuleInstances()方法中主要是这几个方法,其他得处理逻辑与以上方法相似。 this.addRuleSets()类则从web.xml中如果配置了rulesets属性则初始化客户化的RuleSet。 好到此为之,Digest得准备工作已经完成,接下来就是应该解析配置文件了。 Struts 源码中接下来是看web.xml是否配置了多了struts-congfig.xml文件,如果是则解析多个。解析的代码就在this.parseModuleConfigFile(digester, url)中,该方法就是解析配置文件得关键,其实该方法就一个方法,即 digester.parse(url);但是它得作用确是非凡的,主要工作 流程 快递问题件怎么处理流程河南自建厂房流程下载关于规范招聘需求审批流程制作流程表下载邮件下载流程设计 是以下几点 1.​ 调用Digester的public void startElement(String namespaceURI, String localName,String qName, Attributes list)方法。至于为什么会调用这个方法是因为Digester继承了ContentHandler接口而接口是sax在解析配置文件会调startElement()方法,该方法把上面提及得digester实例中在ConfigRuleSet类中addRuleInstances()保存到digester中得Rule类找出来并且调用其Rule类的begin()方法。现在我们拿3个Rule来解释说明 在ConfigRuleSet中的 addRuleInstances()方法中有 digester.addFactoryCreate("struts-config/form-beans/form-bean", new ActionFormBeanFactory(cl)); digester.addSetProperties("struts-config/form-beans/form-bean"); digester.addSetNext("struts-config/form-beans/form-bean", "addFormBeanConfig","org.apache.struts.config.FormBeanConfig"); 在这些方法中把FactoryCreateRule,SetPropertiesRule,SetNextRule三个继承Rule接口得类加入到以struts-config/form-beans/form-bean字符串为Key得Map中去,所以在startElement()中如果执行到form-bean元素的时候,将找出该3个Rule并执行他们得begin()方法。接下来我们为这个3个Rule类做详细解释; 首先是FactoryCreateRule类:该类实际上调用得是新创建得ActionFormBeanFactory()的createObject()方法。如果在form-bean中没有className属性值的话,则将创建默认得org.apache.struts.action.ActionFormBean类。并将该类push到digster中去。 其次是SetPropertiesRule类:该类的begin方法主要功能是将中的name属性和type属性的value做为ActionFormBean类的name 和 type属性注入。 再次是SetNextRule类,该类的执行是在Digest类的endElement()方法中调用的。其中Rule接口中有body()方法,该方法是处理XML 元素是否有Body Text 具体逻辑由继承Rule得子类来处理,但是如果XML元素没有body Text 默认会有个空字符串做完该XML元素得body Text.接着调用Rule类的end()方法,主要功能是调用ModuleConfigImpl的addFormBeanConfig()方法该方法将以xml中得name属性和value属性值以key-value对得方式存到HashMap 的formBeans中去。 以上3个rule类型的介绍完毕,其实针对与struts-config.xml其他元素节点的处理大致上也是如此都有相应的继承Rule,XXXBeanConfig接口的类相应子类进行处理,最终目的就是以key-value的形式存到ModuleConfigImpl的Map中。至于其他类型节点的处理希望读者自己查看源码来理解。 自此关于struts-config.xml解析过程就告一段落。 接下来介绍struts工作原理, 当struts-config.xml解析完毕后,单一个线程访问ActionServlet类的时候,ActionSerVlet就将该线程访问分配到对应的继承Action类中去。其实这是一个典型的中介者模式。 我们发现在ActionServlet的doGet方法和doPost方法都调用的是pocess方法,所以所有得对客户端得控制都在process生成的RequestProcessor类或者其子类中。在struts1.3之前是由 RequestProcessor来处理,而1.3是由ComposableRequestProcessor这个RequestProcessor子类来处理。 关于ComposableRequestProcessor这个类关于request得处理。我不得不在此之前介绍下一个开源项目Commons Chain了这个开源jar包, 它的出现让struts摆脱了硬编码来处理HTTP请求处理,而是使用XML配置的方式来灵活得增加处理的Command。而这些配置的一系列责任链命令则是处理HTTP请求关键。我们先看看这个配置文件 定义一个lookup 的标签,属性 catalogName指定编目明,name指定责任链名 optional 指定即使没有该子链组也不结束父链。 我们看看 编目名为struts 责任链名为servlet-standard得这个为struts处理HTTP请求的责任链。在介绍之前我先简单介绍下关于这个jar包实现原理,在进一步深入之前我们先看看其类图 从类图中我们可以很清楚看到Command 类和Chain类的关系就是组合模式(Composite pattern)[GoF]的例子:Chain不仅由多个Command组成,而且自己也是Command。这使你可以非常简单得将单个命令(Command)替换成由多个命令(Command)组成的链(Chain)。这个由Command对象唯一操作定义的方法代表了一个直接的命令: public boolean execute(Context context); 所以我们在配置文件里面就可以配置出相当灵活的一个处理链流程,如父链嵌套子链,子链在嵌套子链等等。 而所有对Command调用并处理都来自ChainBase这个类的excute()这个方法,它将调用所有在chain链中的Command类,如果其中一个还回得是true,则跳出链结构。 而当有命令抛出错误时链就会非正常结束。在Commons Chain中,如果有命令抛出错误,链的执行就会中断。不论是运行时错误(runtime exception)还是应用错误(application exception),都会抛出给链的调用者。但是许多应用都需要对在命令之外定义的错误做明确的处理。Commons Chain提供了Filter接口来满足这个 要求 对教师党员的评价套管和固井爆破片与爆破装置仓库管理基本要求三甲医院都需要复审吗 。Filter继承了Command,添加了一个名为postprocess的方法。 public boolean postprocess(Context context, Exception exception); 只要Filter的execute方法被调用,不论链的执行过程中是否抛出错误,Commons Chain都将保证Filter的postprocess方法被调用。和servlet的过滤器(filter)相同,Commons Chain的Filter按它们在链中的顺序依次执行。同样,Filter的postprocess方法按倒序执行。你可以使用这个特性实现自己的错误处理。下面是struts中的错误的Filter: Filter 的execute方法按定义的序列调用。然而,它的postprocess方法将在链执行完毕或抛出错误后执行。当一个错误被抛出时, postprocess方法处理完后会返回true,表示错误处理已经完成。链的执行并不会就此结束,但是本质上来说这个错误被捕捉而且不会再向外抛出。如果postprocess方法返回false,那错误会继续向外抛出,然后链就会非正常结束。 在chain-config.xml中为struts处理异常的类便是ExceptionCatcher,它在postprocess中是调用另外一个chainName 为servlet-exception的链对异常进行处理。 那我们在看看servlet-exception链对异常的处理方式:首先是ExceptionHandler类的execute方法,在该方法中,如果没有捕捉到异常,则结束处理,如果有异常则从ActionConfig中或者ModuleConfig中找寻ExceptionConfig,这主要取决我们在 Struts-config.xml中如何配置。如果在 则可以在ActionConfig中找到ExceptionConfig, 而如果在配置文件中配置全局异常处理机制,则可以在ModuleConfig中找到异常处理ExceptionConfig 而ModuleConfig得异常处理机制是大于ActionConfig的。所以如果配置了前者,后者将失去功效。这些配置主要是针对具体异常类型进行处理。比如如果程序运行中抛出了java.io.IOException 那我们就配置成 这样对IOException类型的异常类型用ExceptionHandler类进行处理,当然这个类是必须要继承默认的org.apache.struts.action. ExceptionHandler类的,如果我们没有定制特殊要求我们就可以利用默认的类即可,path=”/error.jsp”为异常转发路径。 至于Struts如实现对异常处理的原理机制,感兴趣得读者读者可以查看org.apache.struts.chain.commands.servlet.ExceptionHandler类的源码,我在这里不再累述。 当异常处理经过control完成后,就就应该转发到View 来显示了。 看到Chain-config.xml文件看到一个PerformForward类,该类不仅是对异常进行转发,同时对正常得Action类执行完毕后的转发也起作用。它决定你是转发到jsp,还是另外一个Servlet。 而关于Commons Chain解析配置文件和struts解析配置文件其实是一致的,都是用Digest,如果大家有兴趣可以查看源码。解析完生成了2个类重要类CatalogBase和ChainBase。 CatalogBase将所有在该Catalog下的chain都包括到一个map中去,ChainBase将在该链下得command或者子链包括到该类得一个数组中去。 介绍完Commons Chain的工作原理,我们接下来介绍Struts如何使用Commons Chain。ActionServlet中得getRequestProcessor(ModuleConfig config) 中得到ComposableRequestProcessor类并且初始化它,调用init();这里调用的是子类ComposableRequestProcessor 得init()方法 在该方法中 主要是得到需要用到命令责任链结构Chain,而这些命令责任脸都来自XML配置文件 初始化后接着就是调用process()方法来处理Http 的请求了。 Command.excute(Context)方法将调用一系列的Command类来处理请求。下面我将拿出几个主要Command来具体介绍。 ExceptionCatcher类是一个异常处理类,它将执行chain 名称为“servlet-exception”所定义的Command 在chain-config.xml定义可以看到: className="org.apache.struts.chain.commands.servlet.PerformForward"/> 而关于这2个command已经已经在前面详细介绍过,在这里不再累述。 而在 链中所定义的Command们就是对Request请求进行处理处理的核心类: 1.SelectLocale类主要功能是为选择Locale存到ActionContext 2.SetOriginalURI将servlet path存到ActionConext中 3.RequestNoCache为HttpServletResponse设置 response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control","no-cache,no-store,max-age=0"); response.setDateHeader("Expires", 1); 4.SelectAction根据访问的path得到具体的ActionMapping 放到ActionContext中去, 5.CreateActionForm 根据ActionMapping的name 属性 创建ActionForm,这里值得注意的就是ActionForm可以有3种生命周期:request,session,application,所以如果配置成request的话,框架将对每个新request重新生成ActionForm,如果配置为Session的话将在一个session中都会还回同一个ActionForm。(关于Struts如何实现ActionForm3种生命周期的详解,我将在另一篇文章中详细解释)如果ActionForm 都不在上述3种生命周期中,struts将生成新的ActionForm。 6.PopulateActionForm类根据request.getParameter(“args”) 注入到 参数到ActionForm中去。 7.ValidateActionForm类为调用ActionForm的validate方法对ActionForm属性值进行有效性校验。 8.SelectInput类 根据中配置的input属性值创建一个ActionForward类,并存到ActionContext当中。但是如果在使用客户化的ControllerConfig类同时设置inputForward为true,那么将会根据input属性值去寻找元素内的name属性值与之相等的ActionForward,如果没有name属性与之匹配则去寻找全局中name属性与之相等的ActionForward 9.ExecuteCommand类 如果我们在 设置catalog,command属性的话,那么在ExecuteCommand中将执行该catalog下的责任链 10.CreateAction类 根据在 中配置的path属性值而与每次Request请求Path相对应时,创建以type属性值的继承Action类的Action子类,并将之存入ApplicationScope,所以在整个应用期间,都只有一个path路径对应的Action类。 11.ExecuteAction 类调用由10.CreateAction创建的Action类子类的execute(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)方法并将返回的ActionForward 存入ActionContext. 12.ExecuteForwardCommand类为ExecuteCommand之类,如果我们在配置文件中配置成 将执行catalog属性配置的责任链 13. PerformForward类根据保存在ActionContext的ActionForward类中的path属性进行跳转到视图或者是另外一个Action进行处理。 14.ExceptionHandler 对链中任意一个执行步骤中产生的Exception进行处理,我们可以客户化异常处理类。 到此为之Struts的处理流程解析就完成了。在以后的文章中我将介绍Struts的标签源码解析。
本文档为【Struts源码解析】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_544402
暂无简介~
格式:doc
大小:379KB
软件:Word
页数:14
分类:互联网
上传时间:2011-02-14
浏览量:25