webx的rundata相关

webx已经开源了,一些东东也贴到这里备份下。

rundata生命周期

rundata构建于doGet方法执行的最初,在pipeline中的finally valves之前commit。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
try {
            //在doGet的最初构造rundata,在rundata构造之后才会去走pipeline的流程
            rundata = getRunData(request, response);

            if (!rundata.isRedirected()) {
                try {
                    Profiler.enter("before request");
                    beforeRequest(rundata);
                } finally {
                    Profiler.release();
                    beforeRequestCalled = true;
                }

                try {
                    Profiler.enter("handle request");
                    handleRequest(rundata);
                } finally {
                    Profiler.release();
                }
            }
        } 

}catch (Throwable e) {
...
} finally {
       try {
              //最后在finally中调用commit方法
             commitRunData(rundata);
                      } catch (Exception e) {
               ...
            } finally {
                if (beforeRequestCalled) {
                    try {
                        Profiler.enter("after request");
                        //考虑到不要让pipeline最后的清理操作影响到rundata内部需要提交的值,所以把这个放在rundata提交之后
                        afterRequest(rundata);
                                     } catch (RuntimeException e) {
                        ...
                    } catch (Error e) {
                        ...
                    } finally {
                        Profiler.release();
                    }
                }
            }

}

rundata的装饰模式

为了能够增强rundata的功能,对其中的request和response进行一层层的包装,将需要的功能一部分一部分的集成进去,就是rundata现在的处理方式。

<service name="RunDataService" class="com.alibaba.webx.service.rundata.DefaultRunDataService">
			<property name="rundata.class" value="com.alibaba.china.common.webx.service.rundata.ChinaRunData" />
			<property name="request.buffered.class"	value="com.alibaba.webx.request.context.buffered.BufferedRequestContextFactory" />
			<property name="request.lazycommit.class" value="com.alibaba.webx.request.context.lazycommit.LazyCommitRequestContextFactory" />
			<property name="request.parser.class" value="com.alibaba.webx.request.context.parser.ParserRequestContextFactory" />
...
</service>

在对rundataService中配置进来一系列的*RequestContextFactory的工厂类,DefaultRundataService集成自RequestContextChainServiceImpl,在这个类中的init方法中有调用initRequestContextFactories方法。

public void init() throws ServiceInitializationException {
        Configuration configuration = getConfiguration();

        initRequestContextFactories(configuration);

        super.init();
}

private void initRequestContextFactories(Configuration configuration)
            throws ServiceInitializationException {
        factories     = new ArrayHashMap();
        configuration = configuration.subset(REQUEST_CONTEXT_FACTORY_PREFIX);

        String classSuffix = "." + REQUEST_CONTEXT_FACTORY_CLASS;

        for (Iterator i = configuration.getKeys(); i.hasNext();) {
            String key = (String) i.next();

            if (key.endsWith(classSuffix)) {
                //取出配置文件中的factory name
                String factoryName = key.substring(0, key.length() - classSuffix.length());

                if (StringUtil.isNotEmpty(factoryName) && !StringUtil.contains(factoryName, ".")) {
                    //根据配置文件中的配置项初始化factorys
                    initRequestContextFactory(factoryName, configuration.subset(factoryName));
                }
            }
        }
    }

 /**
     * 初始化一个request context factory。
     *
     * @throws ServiceInitializationException 如果初始化失败
     */
    private void initRequestContextFactory(String factoryName, Configuration configuration)
            throws ServiceInitializationException {
        String factoryClass = StringUtil.trimToNull(configuration.getString(REQUEST_CONTEXT_FACTORY_CLASS));
        ...

        // 初始化factory
        RequestContextFactory factory;

        try {
            factory = (RequestContextFactory) ClassLoaderUtil.newInstance(factoryClass);
        } catch (ClassInstantiationException e) {
            ...
        } 
        
        //调用factory中的init方法
        factory.init(factoryName, configuration, this);

        //加入到factories数组中去
        factories.put(factoryName, factory);
    }

在调用getRundata方法时,最后回去调用getRequestContext,用所有factory去包装requestContext

/**
     * 取得<code>RequestContext</code>串。
     *
     * @param servletContext <code>ServletContext</code>对象
     * @param request <code>HttpServletRequest</code>对象
     * @param response <code>HttpServletResponse</code>对象
     *
     * @return request context
     */
    public RequestContext getRequestContext(ServletContext servletContext,
                                            HttpServletRequest request, HttpServletResponse response) {
        RequestContext requestContext = new RequestContextImpl(servletContext, request, response);

        for (Iterator i = factories.entrySet().iterator(); i.hasNext();) {
            Map.Entry             entry       = (Map.Entry) i.next();
            RequestContextFactory factory     = (RequestContextFactory) entry.getValue();

            requestContext = factory.getRequestContextWrapper(requestContext);

            // 调用<code>requestContext.prepare()</code>方法
            prepareRequestContext(requestContext);

            // 将requestContext放入request中,以便今后只需要用request就可以取得requestContext。
            RequestContextUtil.setRequestContext(requestContext);
        }

        return requestContext;
    }

在所有的factory类的getRequestContext的方法中,第一条语句都是类似的,就是通过一个AbstractRequestContextWrapper的实现类将wrappedContext封装起来。

public RequestContext getRequestContextWrapper(RequestContext wrappedContext) {
        *RequestContextImpl requestContext = new *RequestContextImpl(wrappedContext);
        ...
    }

然后在new的过程中如果需要对request进行封装,则代码如下,如果需要对response进行封装,代码类似。

public ParserRequestContextImpl(RequestContext wrappedContext) {
        super(wrappedContext);

        setRequest(new RequestWrapper(wrappedContext.getRequest()));
    }

在requestContext接口中,存在prepare和commit方法,在可以在*wrapper中进行实现一些特定的功能

/**
     * 开始一个请求。
     */
    void prepare();

    /**
     * 结束一个请求。
     *
     * @throws RequestContextException 如果失败
     */
    void commit() throws RequestContextException;

在提交的时候的处理如下。

/**
     * 由外到内地调用<code>afterRequest()</code>方法。
     *
     * @param requestContext 要初始化的request context
     *
     * @throws RequestContextException 如果失败
     */
    public void commitRequestContext(RequestContext requestContext)
            throws RequestContextException {
        while (requestContext != null) {
            String message = "Committing request context: "
                             + ClassUtil.getShortClassNameForObject(requestContext) + "("
                             + ObjectUtil.identityHashCode(requestContext) + ")";

            getLogger().debug(message);

            Profiler.enter(message);

            try {
                requestContext.commit();
            } finally {
                Profiler.release();
            }

            requestContext = requestContext.getWrappedRequestContext();
        }
    }

RewriteRequestContextFactory

RewriteRequestContextFactory的init方法中载入配置文件中写入的rules。

/**
     * 初始化factory。
     *
     * @throws ServiceInitializationException 如果失败
     */
    public void init(String factoryName, Configuration configuration,
                     RequestContextChainService requestContextChainService)
            throws ServiceInitializationException {
        super.init(factoryName, configuration, requestContextChainService);

        String[] rewriteConfigs = configuration.getStringArray(REWRITE_CONFIG);

        if (ArrayUtil.isNotEmpty(rewriteConfigs)) {
            Digester digester = getDigester();
            List     ruleList = new ArrayList();

            digester.push(ruleList);

            for (int i = 0; i < rewriteConfigs.length; i++) {
                loadConfig(rewriteConfigs[i], digester);
            }

            rules = (RewriteRule[]) ruleList.toArray(new RewriteRule[ruleList.size()]);

            for (int i = 0; i < rules.length; i++) {
                RewriteRule rule = rules[i];

                checkRule(rule);
            }
        }
    }

rewrite需要parserRequestContext的支持

public RewriteRequestContextImpl(RequestContext wrappedContext, RewriteConfig rewriteConfig) {
        super(wrappedContext);
        this.rewriteConfig = rewriteConfig;

        // 取得parser request context,以便修改参数,查找方式是一层一层去包装
        this.parserRequestContext = (ParserRequestContext) RequestContextUtil.findRequestContext(wrappedContext,
                                                                                                 ParserRequestContext.class);

        if (parserRequestContext == null) {
            throw new IllegalArgumentException("Could not find ParserRequestContext in request context chain");
        }

        // 保存上一层的request对象,以便取得原来的servletPath、pathInfo之类的信息
        this.wrappedRequest = wrappedContext.getRequest();
    }

在prepare中执行操作如下:

  1. 取出当前url,判断是否于对应的rules符合
  2. 通过parserRequestContext处理parameters等
  3. 查看是否是重定向,如果是重定向则拼装出完成的url发出,如果不是则直接替换request中的url
    /**
         * 开始一个请求。
         */
        public void prepare() {
            RewriteRule[] rules = rewriteConfig.getRules();
    
            ...
    
            for (int i = 0; i < rules.length; i++) {
                RewriteRule         rule                 = rules[i];
                MatchResult         ruleMatchResult      = rule.match(path);
                MatchResult         conditionMatchResult = null;
                RewriteSubstitution subs                 = rule.getSubstitution();
    
                // 如果匹配,则查看conditions
                if (ruleMatchResult != null) {
                    conditionMatchResult = rule.matchConditions(ruleMatchResult, wrappedRequest);
                }
    
                // 如果C标志被指定,则除非匹配,否则不去判断余下的规则
                boolean chainRule = ArrayUtil.contains(subs.getFlags(), "chain")
                                    || ArrayUtil.contains(subs.getFlags(), "C");
    
                if (conditionMatchResult == null) {
                    if (chainRule) {
                        break;
                    } else {
                        continue;
                    }
                }
    
                path = subs.substitute(path, ruleMatchResult, conditionMatchResult);
    
                if (!isFullURL(path)) {
                    path = FileUtil.normalizeAbsolutePath(subs.substitute(path, ruleMatchResult,
                                                                          conditionMatchResult));
                }
    
                // 处理parameters
                parameterSubstituted |= subs.substituteParameters(parserRequestContext.getParameters(),
                                                                  ruleMatchResult, conditionMatchResult);
    
                // post substitution处理
                path = firePostSubstitutionEvent(rule, path, parserRequestContext.getParameters(),
                                                 ruleMatchResult, conditionMatchResult);
    
                // 查看重定向标志
                redirectCode = getRedirectCode(subs.getFlags());
    
                // 如果L标志被指定,则立即结束
                boolean lastRule = ArrayUtil.contains(subs.getFlags(), "last")
                                   || ArrayUtil.contains(subs.getFlags(), "L");
    
                if (lastRule) {
                    break;
                }
            }
    
            // 如果path被改变了,则替换request或重定向
            if (!StringUtil.equals(originalPath, path)) {
                ...
          }
        }

你可能感兴趣的:(exception,String,null,iterator,Parameters,Path)