Struts核心代码ActionServlet的运行 2篇

本文深入探讨Struts框架的运行机制,包括ActionServlet的初始化过程、请求处理流程等关键环节,揭示Struts如何实现业务数据流的高效传递。

    早在3年前就开始用Struts了,因该也算用的比较早的一批人。菜鸟的时候也曾经看过别人写的Struts的运行机制,也看过部分代码,但都是草草了事,自己明白了大致方向就结束了。我经常问别人我们写的Action如UserAction是不是Serlvet的,是不是单例的。其实我也没看过实际代码,这样问别人的时候,内心也经常惶恐,惟恐怕从网上看见的资料有假。

     在公司担任技术经理也很长时间了,虽然公司希望自己在开发深度上有所突破,但是本身作为小公司,自己涉及的事情又太多了,时而搞搞bea的portal,时而出去吹吹牛,还经常带几个什么都不会的菜鸟做项目,这几年做的东西也不算少,eai soa eip bmp都有实际的项目经验,但是哪个都没有坚持一路走下去,今天领导要我给公司做java时间比较短的人讲讲struts,正长是个机会,可以把Struts的运行机制,自己好好看看。因为我觉得如果给大家讲hello world,估计大家也不会满意。说了半天废话(我真的很爱说废话诶)下面进入主题吧。

   Struts两大功能,我自己的体会,Struts一个很实用的功能是它的jsp tag,这个是个独立的模块,我们的页面都用他的tag ,虽然现在的extremecomponents也是不错。

  Struts的另一个主要的功能是业务数据流的传递   jsp---->form—》action,这个是整个Struts的核心流程。

  除了这两个主要的功能,剩下的都,都是些具体的基类和接口,方便我们自己的使用,从Struts1.0  1.1 1.2 1.3我们不难看出Struts的趋势也是越来越简单,越来越使用,也不是很一味的追求概念的真理化了。

    其实Struts的运行机制,只要看看ActionServlet就ok了,今天下午花了2个小时看了一边,也算略有收获吧,把原来的一些猜测的内容看清楚出处了。  如果你在次之前,对 单例和多线程不了解,我建议你 补充一下基础概念,因为所有的开源代码里这2个概念都是核心概念,代码也都是围绕着这2个概念去进行的。

    因为Struts也是jsp Servlet机制运行的,所以我们的入口点还先从Servlet的源头开始看,我们打开一个Struts的web项目。打开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-mapping>
    <servlet-name>action</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

我们发现Struts需要在我们的项目里配置一个Servlet  ActionServlet它有几个初始化参数,和监听url里包含.do的url

我们打开ActionServlet类.先看看它的init()方法,因为这个是启动tomcat时就会执行的代码,看看它一开始做了些什么工作
    public void init() throws ServletException {

        initInternal();  
        initOther();
        initServlet();

        // Initialize modules as needed
        getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this);
        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();
        }
        destroyConfigDigester();

    }

 

里面都是些初始化的操作,其实不看代码,我们用脚都能想出来,它肯定是把struts-config.xml文件的内容装载到它封状好的配置信息类里,至于配置信息类,我就不介绍了,无非是些工厂模式或者单例的java类,

  我们先看 initInternal()

 internal = MessageResources.getMessageResources(internalName);  //不用具体看了,是把资源文件装载到类里   if (defaultFactory == null)
            defaultFactory = MessageResourcesFactory.createFactory();
        return defaultFactory.createResources(config);  工厂模式,基本上init里都是这么操作的

initOther() 这个方法读取web.xml里配置的

<init-param>
      <param-name>config</param-name>
      <param-value>/WEB-INF/struts-config.xml</param-value>
    </init-param>

并把这个属性值方法actionSerlvet的 protected String config = "/WEB-INF/struts-config.xml";里,因为servlet是单例的,这个属性也就理所当然的成为全局变量了,其实不是特殊位置,没必要在web.xml里配置了,因为这个属性 有默认值。  initOther() 方法对里convertNull也做了处理,如果你在web,xml 配置的话,它就会给beanutil注册默认转化信息。

initServlet() 也是把web.xml里的信息初始化了一下,放到 getServletContext()中了。对整个流程没影响。

getServletContext().setAttribute(Globals.ACTION_SERVLET_KEY, this); 这句话,很有意思,自己把自己注册到

getServletContext().中,在struts中,经常看见这样的用法。

oduleConfig moduleConfig = initModuleConfig("", config);
        initModuleMessageResources(moduleConfig);
        initModuleDataSources(moduleConfig);
        initModulePlugIns(moduleConfig);
        moduleConfig.freeze();

读取struts-config.xml文件的内容,到类里

********************************************************************************************************************

********************************************************************************************************************

 Struct中ActionServlet的运行历程:  
   
  首先是init()方法  
  ================================  
  1,initInternal()  
  初始化国际语言包(目前好像只支持英文和日文)  
  2,initOther()  
  其他初始化  
  通过读取web.xml中<param-name>config</param-name>的值确定struts-config.xml文件的位置(即使web.xml中没有写config,也会有一个默认位置)  
  通过读取web.xml中<param-name>convertNull</param-name>的值决定是否向后兼容struts   1.0,默认不兼容  
  3,initServlet()  
  初始化ActionServlet的映射和标签库,还是通过读web.xml来进行的。  
  4,将自己保存在ServletContext中。  
  5,初始化模块配置工厂ModuleConfigFactory(大部分为struts1.2新加的功能,作用不明)  
   
  接下来是doGet()/doPost()方法  
  ================================  
  1, 对于Get和Post是使用相同的方法处理的  
  2, 通过解析request得到一个path,这个path决定了将来使用哪一个ActionMapping  
  3, 设置国际化,response的contentType和是否进行缓存  
  4, 这一步比较有意思了,ActionServlet提供了一个简单的返回boolean值的   processPreprocess()方法,可以让我们的子类(Action)选择是否覆盖,如果覆盖了该方法并返回false,则ActionServlet不会再对request进行预处理。  
  5, 根据第2步产生的path来获得相应的配置信息,也就是ActionMapping,保存在request对象里。如果没有找到对应的信息,会产生一个出错信息  
  6, 安全验证,看用户有没有执行本请求的权限  
  7, 如果再配置文件中声明了ActionForm,则创建ActionForm实例(当然,对于普通的ActionForm和动态Form的创建过程是不一样的)  
  8, 根据配置文件中的scope的不同,将ActionForm实例存在request或者session中。  
  9, 接下来是激动人心的一幕:将request流中的数据自动写入ActionForm中。在这里struct通过一套复杂的过程解析了request流,在这里普通表单和“multipart/form-data”复合表单(通常用于上传文件)作了不同的处理,最后应该是通过类映射完成数据写入。在进行这些操作之前,会调用ActionForm的reset方法。  
  10, 如果设置了验证属性,则会调用ActionForm的Validation方法,验证如果失败则尝试转到input页面,如果没有服务器自己产生一个出错页面  
  11, 获取Action实例,在这里struct使用了一个简单的缓存机制,使用了一个HashMap来保存所有的Action实例(自然是以类名为key),如果在HashMap中找不到当前需要的Action,则实例化一个,然后放入HashMap。  
  12, 这一步不太明白,似乎是监测配置文件中是否设置了forward或者include,如果设置了,则转到相应页面,并停止当前的处理。为何这样做,或者说forward和include属性是做什么的,还是不太名字噢,希望高人指点。  
  13, 终于到了这一步……执行Action实例的execute方法,并且获得返回的Forward,呵呵。  
  14, 最后跳转到Forward指向的页面,如果Forward为null则什么也不做。、  
标题基于Python的汽车之家网站舆情分析系统研究AI更换标题第1章引言阐述汽车之家网站舆情分析的研究背景、意义、国内外研究现状、论文方法及创新点。1.1研究背景与意义说明汽车之家网站舆情分析对汽车行业及消费者的重要性。1.2国内外研究现状概述国内外在汽车舆情分析领域的研究进展与成果。1.3论文方法及创新点介绍本文采用的研究方法及相较于前人的创新之处。第2章相关理论总结和评述舆情分析、Python编程及网络爬虫相关理论。2.1舆情分析理论阐述舆情分析的基本概念、流程及关键技术。2.2Python编程基础介绍Python语言特点及其在数据分析中的应用。2.3网络爬虫技术说明网络爬虫的原理及在舆情数据收集中的应用。第3章系统设计详细描述基于Python的汽车之家网站舆情分析系统的设计方案。3.1系统架构设计给出系统的整体架构,包括数据收集、处理、分析及展示模块。3.2数据收集模块设计介绍如何利用网络爬虫技术收集汽车之家网站的舆情数据。3.3数据处理与分析模块设计阐述数据处理流程及舆情分析算法的选择与实现。第4章系统实现与测试介绍系统的实现过程及测试方法,确保系统稳定可靠。4.1系统实现环境列出系统实现所需的软件、硬件环境及开发工具。4.2系统实现过程详细描述系统各模块的实现步骤及代码实现细节。4.3系统测试方法介绍系统测试的方法、测试用例及测试结果分析。第5章研究结果与分析呈现系统运行结果,分析舆情数据,提出见解。5.1舆情数据可视化展示通过图表等形式展示舆情数据的分布、趋势等特征。5.2舆情分析结果解读对舆情分析结果进行解读,提出对汽车行业的见解。5.3对比方法分析将本系统与其他舆情分析系统进行对比,分析优劣。第6章结论与展望总结研究成果,提出未来研究方向。6.1研究结论概括本文的主要研究成果及对汽车之家网站舆情分析的贡献。6.2展望指出系统存在的不足及未来改进方向,展望舆情
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值