ActionServlet类是Struts框架的内置核心控制器组件,它继承了javax.servlet.http.HttpServlet类。Struts的启动通常从
加载ActionServlet开始。Web容器会在首次启动或Struts应用的第一个请求到达时加载ActionServlet。一般情况下都
配置web容器比如tomcat启动的时候加载ActionServlet类,使用<load-on-startup>1</load-on-startup>标签配置启动
加载。
ActionServlet有如下这几个功能
1:读取配置文件Struts-config.xml
ActionServlet加载的时候读取Struts-config.xml文件,将文件对应的配置信息读取到内存中,ActionServlet 根据不同的模块来初始化 ModuleConfig 类,并在其中以XXXconfig 集合的方式保存该模块的各种配置信息,比如 ActionConfig,FormBeanConfig 等。
比如配置文件中的 Action映射定义都保存在 ActionConfig 集合中。相应地有 ControlConfig 集合、FormBeanConfig 集合、ForwardConfig集合和 MessageResourcesConfig 集合等。
这里的模块是为了用于不同用户在同时使用struts-config.xml文件时冲突,每个用户可以定义自己的配置文件,由容器自动去整合配置,每个配置文件相当于一个模块。
2:截取客户端http请求,分发到相应的Action
初始化工作完成之后,ActionServlet准备接收客户请求。针对每个请求,方法 process(HttpServletRequest request, HttpServletResponseresponse) 将被调用。该方法指定具体的模块,然后调用该模块的 RequestProcessor 的 process 方法。
其实根据Servlet的原理,应该调用ActionServlet的doPost()或doGet()方法来处理用户请求,而它们实际上都是调用process()方法具体处理请求的,如下列代码:
public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException { process(request, response); }
public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException { process(request, response); }
protected void process(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //根据请求选择适当的应用模块 ModuleUtils.getInstance().selectModule(request, getServletContext()); ModuleConfig config = getModuleConfig(request); //获取模块相关的RequestProcesser实例 RequestProcessor processor = getProcessorForModule(config); if (processor == null) { processor = getRequestProcessor(config); } //调用processor实例的process()方法处理请求 processor.process(request, response); }
在上面我们看到ActionServlet的process()方法中实际处理用户请求的是RequestProcessor类的process()方法。Struts框架只允许应用程序中存在一个ActionServlet类,但每个应用程序模块都有各自的RequestProcessor类实例。在ActionServlet的process()方法中,一旦选择了正确的应用程序模块,就会调用相应模块RequestProcessor实例的process()方法来处理请求。RequestProcessor类的process方法如下:
//摘自RequestProcessor public void process(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException { //用一个特殊的包装对象把Muiltipart请求包装起来 request = processMultipart(request); //验证我们用来选择映射的路径组件 String path = processPath(request, response); if (path != null) { if (log.isDebugEnabled()) log.debug("Processing a '" + request.getMethod() + "' for path '" + path + "'"); //有请求时, 为当前用户选择一个Locale对象 processLocale(request, response); //有请求时,设置内容类型和no-caching字头 processContent(request, response); processNoCache(request, response); if (processPreprocess(request, response)) { processCachedMessages(request, response); //验证这个请求的映射 ActionMapping mapping = processMapping(request, response, path); if (mapping != null && processRoles(request, response, mapping)) { //处理和这个请求相关的任何ActionForm bean ActionForm form = processActionForm(request, response, mapping); processPopulate(request, response, form, mapping); if (processValidate(request, response, form, mapping)&& processForward(request, response, mapping)&& processInclude(request, response, mapping)) { //创建或获取Action实例来处理这项请求 Action action = processActionCreate(request, response, mapping); if (action != null) { //调用Action实例本身 ActionForward forward = processActionPerform(request, response,action, form, mapping); //处理所返回的ActionForward实例 processForwardConfig(request, response, forward); } } } } } }
ActionServlet在 ActionConfig 中找出对应于该请求的 Action 子类,如果没有对应的 Action,控制器直接将请求转发给 JSP或者静态页面。否则控制器将请求分发至具体 Action 类进行处理。
3:从请求中获取数据填充 FormBean(如果需要)
在控制器调用具体 Action 的 execute方法之前,ActionForm 对象将利用 HTTP 请求中的参数来填充自己(可选步骤,需要在配置文件中指定)。具体的 ActionForm 对象应该是ActionForm 的子类对象,它其实就是一个 JavaBean。
需要特别说明的是,Struts的配置文件struts-config.xml作为ActionServlet的一个初始化参数值在web.xml文件中声明。另外,ActionServlet的URL形式是*.do,这样当在浏览器地址输入任何后缀为*.do的URL时,系统都会映射到ActionServlet。