struts的具体执行过程

本文详细解析了Struts框架的工作流程,从用户请求开始到最终页面显示的过程,包括配置文件解析、ActionServlet工作原理、ActionForm表单填充及验证、Action执行、ActionForward转发等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面以用户登录为例:部分需要参考的配置文件如下:

<form-beans >
    <form-bean name="loginForm" type="com.hundsun.struts.form.LoginForm" />

</form-beans>

  <action-mappings >
    <action
      attribute="loginForm"
      input="/login.jsp"
      name="loginForm"
      path="/login"
      scope="request"
      validate="true"
      type="com.hundsun.struts.action.LoginAction" />

  </action-mappings>

  struts有一个中央控制器ActionServlet,负责处理用户的url请求,ActionServlet在web.xml文件中配置,它继承了HttpServlet,其实就是一个普通的servlet。ActionServlet中有两个方法,如下:

  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);

    }

ActionServlet会自动调用doGet()或doPost()方法。从中可以看出doGet(),doPost()直接调用了process(request, response)方法:

  protected void process(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {

        ModuleUtils.getInstance().selectModule(request, getServletContext());
        ModuleConfig config = getModuleConfig(request);

        RequestProcessor processor = getProcessorForModule(config);
        if (processor == null) {
           processor = getRequestProcessor(config);
        }
        processor.process(request, response);

    }

process方法继续调用RequestProcessor 的process(request, response)方法,process的部分源代码如下:

   public void process(HttpServletRequest request,
                        HttpServletResponse response){

        request = processMultipart(request);
        
        String path = processPath(request, response);
        if (path == null) {
            return;
        }
        ActionMapping mapping = processMapping(request, response, path);
        if (mapping == null) {
            return;
        }

        ActionForm form = processActionForm(request, response, mapping);
        processPopulate(request, response, form, mapping);  
   
        if (!processForward(request, response, mapping)) {
            return;
        }

        Action action = processActionCreate(request, response, mapping);
        if (action == null) {
            return;
        }

        ActionForward forward =
            processActionPerform(request, response,
                                 action, form, mapping);
        processForwardConfig(request, response, forward);

    }

processMultipart(request);主要是用来处理file域,其实就是重写request得到属性的方法。

String path = processPath(request, response);截取用户提交的url地址,该方法主要的两句代码如下:

     int slash = path.lastIndexOf("/");
        int period = path.lastIndexOf(".");

此时的path="/login";接着我们来看

ActionMapping mapping = processMapping(request, response, path);主要源代码如下:

 protected ActionMapping processMapping(HttpServletRequest request,
                                           HttpServletResponse response,
                                           String path)
        throws IOException {

        ActionMapping mapping = (ActionMapping)
            moduleConfig.findActionConfig(path);

        ActionConfig configs[] = moduleConfig.findActionConfigs();
        for (int i = 0; i < configs.length; i++) {
            if (configs[i].getUnknown()) {
                mapping = (ActionMapping) configs[i];
                request.setAttribute(Globals.MAPPING_KEY, mapping);
                return (mapping);
            }
        }

    }
我们先看ActionMapping mapping = (ActionMapping)moduleConfig.findActionConfig(path)方法。

moduleConfig类是个接口,他的实现类是moduleConfigImpl

   public ActionConfig findActionConfig(String path) {

        ActionConfig config = (ActionConfig) actionConfigs.get(path);
        return config;

    }

actionConfigs是个hashmap通过key=path="/login"获取,actionConfigs的这个值是在struts初始化的时候放进去的。

ok,现在ActionMapping已经得到,一个ActionMapping就是对应一个<action/>标签,它的key为 <action/>标签中的path的值,这里为"/login",其余的<action/>标签中的属性值就是value。

 下面看:ActionForm form = processActionForm(request, response, mapping);

   protected ActionForm processActionForm(HttpServletRequest request,
                                           HttpServletResponse response,
                                           ActionMapping mapping) {

       
        ActionForm instance = RequestUtils.createActionForm
            (request, mapping, moduleConfig, servlet);
        if (instance == null) {
            return (null);
        }

        if ("request".equals(mapping.getScope())) {
            request.setAttribute(mapping.getAttribute(), instance);
        } else {
            HttpSession session = request.getSession();
            session.setAttribute(mapping.getAttribute(), instance);
        }
        return (instance);

    }

先看ActionForm instance = RequestUtils.createActionForm(request, mapping, moduleConfig, servlet);

    public static ActionForm createActionForm(
            HttpServletRequest request,
            ActionMapping mapping,
            ModuleConfig moduleConfig,
            ActionServlet servlet) {

        // Is there a form bean associated with this mapping?
        String attribute = mapping.getAttribute();
        if (attribute == null) {
            return (null);
        }
        String name = mapping.getName();
        FormBeanConfig config = moduleConfig.findFormBeanConfig(name);

        ActionForm instance = lookupActionForm(request, attribute, mapping.getScope());

        return createActionForm(config, servlet);
    }

String attribute = mapping.getAttribute();是来找attribute="loginForm"如果没有就直接返回,因为formbean我们不一定要创建。

这句String name = mapping.getName();是得到form的名字 name="loginForm"

接着是FormBeanConfig config = moduleConfig.findFormBeanConfig(name);

    public FormBeanConfig findFormBeanConfig(String name) {

        return ((FormBeanConfig) formBeans.get(name));

    }

formBeans也是个hashmap,里面存放的就是一个个<form-bean/>标签这里例子中的key="loginForm"

现在我们得到了一个FormBeanConfig。接着:

       ActionForm instance = lookupActionForm(request, attribute, mapping.getScope());

   private static ActionForm lookupActionForm(HttpServletRequest request, String attribute, String scope)
    {
     
        ActionForm instance = null;
        HttpSession session = null;
        if ("request".equals(scope)) {
            instance = (ActionForm) request.getAttribute(attribute);
        } else {
            session = request.getSession();
            instance = (ActionForm) session.getAttribute(attribute);
        }

        return (instance);
    }

先在request和session找下是否存在这个FormBean,如果有就直接返回。如果instance为空,就继续创建createActionForm(config, servlet);

    public static ActionForm createActionForm(FormBeanConfig config, ActionServlet servlet)
    {
        ActionForm instance = null;

            instance = config.createActionForm(servlet);
           
        return (instance);

    }

    public ActionForm createActionForm(ActionServlet servlet)
        throws IllegalAccessException, InstantiationException {

        Object obj = null;

        // Create a new form bean instance
        if (getDynamic()) {
            obj = getDynaActionFormClass().newInstance();
        } else {
            obj = formBeanClass().newInstance();
        }

        ActionForm form = null;
        if (obj instanceof ActionForm) {
            form = (ActionForm)obj;
        } else  {
            form = new BeanValidatorForm(obj);
        }

        return form;

    }

通过动态代理得到一个formBean。

好了,现在我们看  Action action = processActionCreate(request, response, mapping);

 protected Action processActionCreate(HttpServletRequest request,
                                         HttpServletResponse response,
                                         ActionMapping mapping)
        throws IOException {

        String className = mapping.getType();
        Action instance = null;
        synchronized (actions) {
            instance = (Action) actions.get(className);
            if (instance != null) {
                return (instance);
            }
                instance = (Action) RequestUtils.applicationInstance(className);
      
            instance.setServlet(this.servlet);
            actions.put(className, instance);
        }

        return (instance);

    }

String className = mapping.getType();得到的就是action的完整路径名,这里为com.hundsun.struts.action.LoginAction

synchronized (actions) actions是个hashmap,loginAction存在就返回,这里进行了同步,也就是说只会创建一个loginAction实例。接下看下面的代码,如果不存在就调用instance = (Action) RequestUtils.applicationInstance(className)

  public static Object applicationInstance(String className)
            throws ClassNotFoundException, IllegalAccessException, InstantiationException {

        return (applicationClass(className).newInstance());

    }

返回一个loginAction实例。

 ActionForward forward =processActionPerform(request, response,action, form, mapping);

    protected ActionForward
        processActionPerform(HttpServletRequest request,
                             HttpServletResponse response,
                             Action action,
                             ActionForm form,
                             ActionMapping mapping)
        throws IOException, ServletException {

            return (action.execute(mapping, form, request, response)); 

}

这里直接调用了action类的execute方法,返回一个ActionForward,ActionForward类里存放着对应<action/>标签下的所有的forward信息。最后执行processForwardConfig(request, response, forward);

    protected void processForwardConfig(HttpServletRequest request,
                                        HttpServletResponse response,
                                        ForwardConfig forward)
        throws IOException, ServletException {

        if (forward == null) {
            return;
        }

        String forwardPath = forward.getPath();
        String uri = null;
        if (forwardPath.startsWith("/")) {
            uri = RequestUtils.forwardURL(request, forward, null); 
        } else {
            uri = forwardPath;
        }
        
        if (forward.getRedirect()) {
            if (uri.startsWith("/")) {
                uri = request.getContextPath() + uri;
            }
            response.sendRedirect(response.encodeRedirectURL(uri));
            
        } else {
            doForward(uri, request, response);
        }

    }

。。。。。

分两种情况进行转发,一种是: response.sendRedirect(response.encodeRedirectURL(uri));

另二种是:doForward(uri, request, response);该方法里主要的两句代码是:
      RequestDispatcher rd = getServletContext().getRequestDispatcher(uri);

     rd.forward(request, response);

OVER!

 

 

转自http://lovedance.blogbus.com/logs/36997014.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值