webx已经开源了,一些东东也贴到这里备份下。
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的功能,对其中的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的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中执行操作如下:
/** * 开始一个请求。 */ 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)) { ... } }