struts1源码学习7,action处理核心ComposableRequestProcessor

先做个铺垫,先回忆一下ActionServlet.initChain的细节

 public void addRuleInstances(Digester digester) {

        // Add rules for a catalog element
        digester.addRule("*/" + getCatalogElement(),
                         new ConfigCatalogRule(nameAttribute, catalogClass));
        digester.addSetProperties("*/" + getCatalogElement());

        // Add rules for a chain element
        digester.addObjectCreate("*/" + getChainElement(),
                                 getChainClass(),
                                 getClassAttribute());
        digester.addSetProperties("*/" + getChainElement());
        digester.addRule("*/" + getChainElement(),
                         new ConfigRegisterRule(nameAttribute));

        // Add rules for a command element
        digester.addObjectCreate("*/" + getCommandElement(),
                                 null,
                                 getClassAttribute());
        digester.addSetProperties("*/" + getCommandElement());
        digester.addRule("*/" + getCommandElement(),
                         new ConfigRegisterRule(nameAttribute));

        // Add rules for a define element
<span style="white-space:pre">	</span>//getNameAttribute()实际的值是"name",后面那个参数是"className"
        digester.addRule("*/" + getDefineElement(),
                         new ConfigDefineRule(getNameAttribute(),
                                              getClassAttribute()));

    }
这里面有个特别的地方,在于define标签的处理。看ConfigDefineRule.begin代码

public void begin(String namespace, String name, Attributes attributes)
        throws Exception {

        // Extract the actual name and implementation class to use
<span style="white-space:pre">	</span>//获取name属性值
        String nameValue = attributes.getValue(nameAttribute);
<span style="white-space:pre">	</span>//获取className属性值chain-config.xml
        String classValue = attributes.getValue(classAttribute);
        //默认情况下org/apache/struts/chain/chain-config.xml<define name="lookup" className="org.apache.commons.chain.generic.LookupCommand"/> 
        digester.addObjectCreate("*/" + nameValue, classValue);
        digester.addSetProperties("*/" + nameValue);
        digester.addRule("*/" + nameValue,
                         new ConfigRegisterRule(nameAttribute));

    }
org.apache.commons.chain.generic.LookupCommand
LookupCommand)


1、init方法

  public void init(ActionServlet servlet, ModuleConfig moduleConfig)
        throws ServletException {
        LOG.info(
            "Initializing composable request processor for module prefix '"
            + moduleConfig.getPrefix() + "'");
        //清空actions,然后赋值servlet和moduleConfig
        super.init(servlet, moduleConfig);
        //赋值,this.catalogFactory = CatalogFactory.getInstance();
        initCatalogFactory(servlet, moduleConfig);
        //拿到ControllerConfig配置
        ControllerConfig controllerConfig = moduleConfig.getControllerConfig();
        //这个默认值是struts
        String catalogName = controllerConfig.getCatalog();
        /* CatalogFactory.getInstance().getCatalog
         * 这个在catalogFactory实际上是在ActionServlet.init中的initChain来赋值初始化的
         * 在ActionServlet.initChain中,解析xml时,会根据catalog标签生成一个org.apache.commons.chain.impl.CatalogBase。
         * 而catalogFactory中有两个属性一个是catalog,另一个是catalogs(Map),这两个属性专门存放这些
         * CatalogBase对象,其中没有name的会放在catalog,有name的则以键值对的形式放入catalogs中
         */
        catalog = this.catalogFactory.getCatalog(catalogName);


        if (catalog == null) {
            throw new ServletException("Cannot find catalog '" + catalogName
                + "'");
        }
        //默认值是servlet-standard
        String commandName = controllerConfig.getCommand();
        /*
         * 找到名字是servlet-standard的command
         * 回忆一下,在Action.initChain中,碰到chain标签时会这样解析。
         * 1、 digester.addObjectCreate生成org.apache.commons.chain.impl.ChainBase对象
         * 2、 digester.addSetProperties给对象属性赋值
         * 3、 digester.addRule(/chain",new ConfigRegisterRule(nameAttribute));
         * 其中rule,是这样处理的。拿到刚刚生成的ChainBase,和在digester栈中ChainBase的前一个对象(称之为next对象),
         * 接着调用next.addCommand方法,ChainBase作为参数
         * 这个next必须实现Command接口
         * 但是,如果这个next是Catalog,那么调用的是addCommand(name,chainBase),
         * 如果next是ChainBase对象,那么调用addCommand(chainBase)
         * 差别就在于有没name
         * 
         */
        command = catalog.getCommand(commandName);


        if (command == null) {
            throw new ServletException("Cannot find command '" + commandName
                + "'");
        }
        //默认情况下,这个值是空的
        this.setActionContextClassName(controllerConfig.getProperty(
                ACTION_CONTEXT_CLASS));
    }
2、process方法

    public void process(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
        // Wrap the request in the case of a multipart request
    	//处理"multipart/form-data",即上传文件的表单时,将request包装成MultipartRequestWrapper
        request = processMultipart(request);
        /*这里建立一个ActionContext,如果用户没指定actionContextClass的话,
         * 默认new ServletActionContext(servletContext, request, response)
         * 这个ActionContext包含了request,response,servletContext和ModuleConfig
         */
        // Create and populate a Context for this request
        ActionContext context = contextInstance(request, response);

        // Create and execute the command.
        try {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Using processing chain for this request");
            }
            //执行ChainCommand,实际上这个command就是chainBase
            command.execute(context);
        } catch (Exception e) {
            // Execute the exception processing chain??
            throw new ServletException(e);
        }

        // Release the context.
        context.release();
    }


猜你喜欢

转载自blog.csdn.net/wtc860104/article/details/38400255