最近在做一个简单的搜索工具, 目的是让用户能够更快捷的查找到合适自己的测试用例.

考虑到大多数身边的小伙伴都用 webx 来进行搭建服务, 而且加上最近已经有部分业务已经用到了 webx, 所以决定上 webx 这条已经运行了很久的大船..

首先贴上 webx 的官方首页

先创建一个工程

mvn archetype:generate \
-DgroupId=com.alibaba.webx \
-DartifactId=tutorial1 \
-Dversion=1.0-SNAPSHOT \
-Dpackage=com.alibaba.webx.tutorial1 \
-DarchetypeArtifactId=archetype-webx-quickstart \
-DarchetypeGroupId=com.alibaba.citrus.sample \
-DarchetypeVersion=1.8 \
-DinteractiveMode=false

接着执行mvn jetty:run-war之后在浏览器里打开localhost:8081就能看到例子的样子了.

这样一个简单的 webx 应用就可以运行起来了

粗略的看了下例子的源码,但发现生成的几个例子的 java 类并没有明显的调用关系.

那么web 程序是如何run 起来的呢.

接着就产生了如下几个疑问:

  1. execute 函数为何能够被调用到
  2. doChinese 函数为何能够被调用到
  3. JAVA 类如何与 vm 文件对应起来
  4. 为什么链接的结尾有 do,htm,分别有什么意义
  5. 表单验证的运行原理是什么
  6. 请求过来之后的处理流程
  7. 如何满足我的要求

1. execute 函数为何能够被调用到,doChinese 函数为何能够被调用起来

先看看 execute 函数, 随便找一个 execute 函数,加上断点,看看调用栈
1

能够看到执行 execute 函数的地方是 performScreenModule

大致的代码是这样的

 /** 执行screen模块。 */
protected Object performScreenModule(TurbineRunData rundata) {
ModuleFinder finder = new ModuleFinder(rundata.getTarget());

// 如果设置了template,则默认打开layout
rundata.setLayoutEnabled(true);

try {
Module module = finder.getScreenModule();

// 当指定了templateName时,可以没有的screen module,而单单渲染模板。
// 这样就实现了page-driven,即先写模板,必要时再写一个module class与之对应。
if (module != null) {
// 将event传入screen。
ScreenEventUtil.setEventName(rundata.getRequest(), finder.event);

try {

if (module instanceof ModuleReturningValue) {
return ((ModuleReturningValue) module).executeAndReturn();
} else {
module.execute();
}
} finally {
ScreenEventUtil.setEventName(rundata.getRequest(), null);
}
} else {
if (isScreenModuleRequired()) {
throw new ModuleNotFoundException("Could not find screen module: " + finder.moduleName);
}
}
} catch (ModuleLoaderException e) {
throw new WebxException("Failed to load screen module: " + finder.moduleName, e);
} catch (Exception e) {
throw new WebxException("Failed to execute screen: " + finder.moduleName, e);
}

return null;
}

从代码可以看出,首先找到对应的 module, 接着执行 executeAndReturnexecute

我们接着finder.getScreenModule() 继续深入下去,就会找到最终 module 生成的地方

public class DataBindingAdapterFactory extends AbstractDataBindingAdapterFactory {
public Module adapt(String type, String name, Object moduleObject) {
ModuleInfo moduleInfo = new ModuleInfo(type, name);
Class<?> moduleClass = moduleObject.getClass();
Method executeMethod = getMethod(moduleClass, "execute");

if (executeMethod != null) {
FastClass fc = FastClass.create(moduleClass);
FastMethod fm = fc.getMethod(executeMethod);

// 对于action,可被“跳过”执行。
boolean skippable = "action".equalsIgnoreCase(type);

return new DataBindingAdapter(moduleObject, getMethodInvoker(fm, moduleInfo, skippable));
}

return null;
}
}

到这里应该就可以得出结论了, execute 是在代码里写死了, doXXX也是一样的… 至于moduleClass 的获取方式是直接从 request url 里解析出来的,所以 java class 的名字需要有与url 一一对应起来

记录一张官方文档的图片说明 webx Turbine 的组成部分
2 • Screen,代表页面的主体。
• Layout,代表页面的布局。
• Control,代表嵌在screen和layout中的页面片段。

2. 为什么链接的结尾有 do,htm 分别有什么意义

这个可以在 Webx3_Guide_Book.pdf 4.3 处理页面的基本流程里找到.

‘.do’ 后缀不是必须的,另外也是可以自己定义的.例如 “.go” 也是可以的.但需要在pipeline.xml 里定义好

3. 表单验证的运行原理是什么

这个问题也可以在Webx3_Guide_Book.pdf第九章得到完美的解答. 了解相应的规则就好

4. 请求过来之后的处理流程以及如何满足我的要求

当一个HTTP请求到达时,首先由WebxFrameworkFilter, 这个是在 web.xml里约定好的…

不过在知道 execute 如何被调用到之后, 你就会发现 execute 函数是可以带参数的,所以对于我来说只需要改造一下 execute 函数就可以满足我的需求了

public void execute(HttpServletResponse response, HttpServletRequest request) throws Exception {
// 设置content type,但不需要设置charset。框架会设置正确的charset。
response.setContentType("text/plain");

// 如同servlet一样:取得输出流。
PrintWriter out = response.getWriter();

Map map = request.getParameterMap();

out.println(searchResultFromParam(map));
}

这样客户端发送 get 或者 post 请求, webx 就可以处理并返回查询结果…
OK 暂时就到这里吧, 以后如果需要深入了解,再来追加….

学习 webx 花了八个番茄钟, 写该文章花了一个番茄钟.