rose的portal是一个非常不错的web服务端技术
传统的web服务器对一个request请求的处理是串行的
只有所有逻辑处理完后才返回数据给页面渲染
这样的好处固然简单,但是也有极为严重的缺陷
如果其中一段代码发生异常将可能造成请求处理中断,直接导致500错误
而rose的portal技术则是一种并发的web服务端技术
这里所讲的并发是指portal将request的处理分成了多个并发处理的window
portal把控整个处理过程,并分发处理请求给每个window
每个window只负责处理自己的逻辑
页面渲染时所需要的数据也由对应的window提供,最终的请求返回由portal控制
详细的rose-portal介绍可点击这里 http://code.google.com/p/paoding-rose/wiki/Rose_Portal_Demo
portal使用的是多线程的思想来实现这个并发处理的portal、window机制
//portal的使用是基于rose的,同样也是一个controller ,如下所示
public class ShowController {
// 标注@Get,表示这个方法要处理的是对/portal的GET请求
// 在主控控制方法上声明Portal参数即表示这个页面是portal,就这样!
@Get
@PortalSetting(timeout = 3000000)
public String home(Invocation inv, Portal portal) throws Exception {
// 使用addWindow向这个portal页面加入各种子信息(我们成为窗口)
portal.addWindow( "weather", "/windows/weather" );
// 第一个参数是用于标识该窗口,使得portal页面中可以引用到这个窗口的 html
// 第二个参数表示这个窗口的地址(可以包含参数),这个地址等价于forward的地址(也就是这里只要能forward的地址都可以,无论是否是rose框架的,甚至可以是一个 jsp页面)
// 因此,地址没有说一定要以"/windows"开始
portal.addWindow( "todo", "/windows/todo?name=value" );
inv.addModel( "word", "hello world" );
return "portal-home";
}
}
//可以把portal想象成我们要渲染的页面,每个window就是页面中的一个模块
//portal.addWindow 把各个页面模块添加到portal 中
//下面是addWindow 的代码实现
//这里可以看到window 实现的整个过程:
//创建window实例、并创建window处理任务,最终会交由executorService 来执行
public Window addWindow(String name, String windowPath, Map<String, Object> attributes) {
// 创建 窗口对象
WindowImpl window = new WindowImpl((PortalImpl) this, name, windowPath);
//
if (attributes != null) {
synchronized (attributes) {
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
window.set(entry.getKey(), entry.getValue());
}
}
}
// 定义窗口任务
WindowTask task = new WindowTask(window);
// 注册到相关变量中
synchronized (windows ) {
this.windows .add(window);
}
this.invocation .addModel(name, window);
// 事件侦听回调
onWindowAdded(window);
// 提交到执行服务中执行
Future<?> future = submitWindow( this.executorService , task);
window.setFuture(future);
// 返回窗口对象
return window;
}
//window 对象实例化过程主要是设置portal 控制器、window自身的属性如name、path
// 另外很重要的就是设置window的request和response对象,这是非常出色和有趣的构建
public WindowImpl(PortalImpl portal, String name, String windowPath) {
this.portal = portal;
this.name = name;
this.path = windowPath;
this.request = new WindowRequest(portal.getRequest());
this.response = new WindowResponse( this);
}
// 有了window实例,就可以创建对应的window task
final class WindowTask implements Runnable {
private static final Log logger = LogFactory.getLog(WindowTask.class);
private final WindowImpl window ;
public WindowTask (WindowImpl window) {
if (window == null) {
throw new NullPointerException("window");
}
this.window = window;
}
public WindowImpl getWindow() {
return window ;
}
// 可以看到,一个window task 是一个转发请求
// 通过这样的方式来细分化一个request请求,这样的切分思想实在是充满了智慧
@Override
public void run() {
try {
// started
window.getPortal().onWindowStarted(window );
// doRequest
final HttpServletRequest request = window .getRequest();
final RequestDispatcher rd = request.getRequestDispatcher(window .getPath());
request.setAttribute( "$$paoding-rose-portal.window" , window);
rd.forward(request, window.getResponse());
// done!
window.getPortal().onWindowDone(window );
} catch (Throwable e) {
logger.error("" , e);
window.setThrowable(e);
window.getPortal().onWindowError(window );
}
}
.......
}
// 每个window task请求会交由一个新的线程去处理
// 这个多线程的任务机制是由executor框架来管理的
protected Future<?> submitWindow(ExecutorService executor, WindowTask task) {
Future<?> future = executor.submit(task);
return new WindowFuture(future, task.getWindow());
}
// 转发后的请求将会重新走一遍rosefilter的处理流程