天天看點

人人網 paoding 旗下 rose 項目實作伺服器端 portal建立控制器window頁面并發數配置進階話題

“portal”一詞中文翻譯為“門戶”,所謂門戶是指各種資訊的內建。

rose portal基于rose架構,是rose的一個插件。這個技術不是基于JavaEE的portlet規範,您隻需要使用标準的servlet容器即可實作,而且更簡單。

本示例示範如何使用rose portal (基于servlet規範),在一個門戶可以顯示兩個獨立的“資訊”

建立控制器

1個是Portal主要,另外2個是視窗控制器 1) 在controllers或子目錄下建立Portal控制器:PortalController,建立處理方法,并聲明Portal參數

package ninja.paoding_rose.test.controllers;

import net.paoding.rose.web.annotation.Path;
import net.paoding.rose.web.annotation.rest.Get;
import net.paoding.rose.web.portal.Portal;

@Path("portal")
public class PortalController {
	// 标注@Get,表示這個方法要處理的是對/portal的GET請求
	// 在主要控制方法上聲明Portal參數即表示這個頁面是portal,就這樣!
	@Get
	public String home(Portal portal) throws Exception {
		// 使用addWindow向這個portal頁面加入各種子資訊(我們成為視窗) 
		portal.addWindow("docin","/windows/docin"); 
		// 第一個參數是用于辨別該視窗,使得portal頁面中可以引用到這個視窗的html //
		// 第二個參數表示這個視窗的位址(可以包含參數),這個位址等價于forward的位址(也就是這裡隻要能forward的位址都可以,無論是否是rose架構的,甚至可以是一個jsp頁面)
		// // 是以,位址沒有說一定要以"/windows"開始
		portal.addWindow("ninja","/windows/ninja?name=value");
		return "portal_page"; 
	}
}
           

 2) 在controllers.windows下建立可被/windows/docin,/windows/ninja 通路的控制器以及方法 DocinController.java

package ninja.paoding_rose.test.controllers.windows;

import net.paoding.rose.web.Invocation;
import net.paoding.rose.web.annotation.Path;
import net.paoding.rose.web.annotation.rest.Get;

@Path("docin")
public class DocinController {
	// 這個方法處理"/windows/weather",它隻是傳回一串中文,而非jsp、vm等頁面
	@Get
	public String docin(Invocation inv) {
		return "@豆丁豆丁豆丁豆丁豆丁豆丁豆丁!";
	}
}
           

 NinjaController.java

package ninja.paoding_rose.test.controllers.windows;

import java.util.ArrayList;
import java.util.List;

import net.paoding.rose.web.Invocation;
import net.paoding.rose.web.annotation.Path;
import net.paoding.rose.web.annotation.rest.Get;
import net.paoding.rose.web.portal.Window;

@Path("ninja")
public class NinjaController {
	// 在控制器使用全局變量并不好,在此僅是一個示範而已
	private int count;

	// 方法名是什麼不要緊,關進是@Get代表了這個方法用于處理對/ninja的GET請求
	@Get
	public String ninja(Invocation inv, Window window) {
		List<String> list = new ArrayList<String>();
		list.add("偷襲");
		list.add("忍術");
		list.add(String.valueOf(count++));
		inv.addModel("todolist", list); //
		// 傳回頁面,rose将從這個子產品對應的/views/windows下找名字以ninja開始的頁面
		return "ninja";
	}
}
           

portal頁面 

webapp/views下建立PortalController需要的portal_page.jsp (這裡亦可以用rose 所支援的.vm檔案)

<%@ page language="java" contentType="text/html; charset=utf-8"
	pageEncoding="utf-8"%>
<html>
<head>
<link href="/static/portal.css" target="_blank" rel="external nofollow"  rel="stylesheet" type="text/css" media="all" /> 
<title>Portal</title>
</head>
<body>
<h2>Portal</h2>
<div class="window">
<div class="title">豆丁</div>
<!--這裡使用$weather的"weather"即是第一個window的辨別-->
<div class="content">${docin}</div>
</div>
<div class="window">
<div class="title">忍者</div>
<!--$todo實際是一個Window對象,velocity會調用其toString()輸出html的-->
<div class="content">${ninja}</div>
</div>
</body>
</html>
           

window頁面

webapp/views/windows建立ninjaController需要的頁面 ninja.jsp (亦可以用ninja.vm 但寫法很不同。)

<%@ page import="java.util.*" %>
<ul>
 <%
	List<String> result = (List<String>)request.getAttribute("todolist");
	for(String oneItem : result){
%>
	<li><%=oneItem %></li>
<%
	}
%>
</ul>

           

并發數配置

在web.xml的<web-app>下配置并發參數值:

        <context-param> 
                <param-name>portalExecutorCorePoolSize</param-name> 
                <param-value>200</param-value> 
        </context-param>      

如果沒有配置以上參數,預設portalExecutorCorePoolSize取1,相當于除了http主線程外隻有另外1個執行線程, 這對程式的正确性沒有任何影響,隻是并發能力下降了,整個portal的執行時間也會變長。

進階話題

1) 可以在PortalController.home方法上設定@PortalSetting(timeout = 100)表示最多等待各個視窗100ms(包括window的頁面渲染耗費時間)

2) 可以通過引入xiaonei-commons-interceptors的@Throughput(maxConcurrent = 20)放置在window的xxx方法上,控制最多并發數

3) 可在web.xml配置全局參數設定poral執行器的線程池參數:portalExecutorCorePoolSize、portalExecutorMaxPoolSize、portalExecutorKeepAliveSeconds

參數意義分别參考java.util.concurrent.ThreadPoolExecutor的corePoolSize、maximumPoolSize、keepAliveTime說明

4) 在portal-home頁面中的$weather實際是一個net.paoding.rose.web.portal.Window對象,是以可通過$weather.success 判斷window的執行是否完成并且是200的,通過$weather.statusCode等了解具體的執行情況。詳細請參考net.paoding.rose.web.portal.Window類屬性清單。

5) 可在window的控制器TodoController.xxx方法中聲明Window window對象,通過window.setTilte(title)或window.set(name, value)相關屬性,并在portal-home.vm使用$todo.title 在todo.vm中,則除了使用todo的名字使用$todo.title,也可以通過$window.title來使用。每個$window在不同的視窗的頁面代表自己的Window對象,不會“亂串”

啟動後,通路http://[yourlocal]/[yourprojectname]/portal

可以看到 兩個div(這裡可以叫做window) 分别通過不同的controller 傳回資料。

想了解vm頁面用法請參考:

http://code.google.com/p/paoding-rose/wiki/Rose_Portal_Demo

此連結為paoding-rose的project home 裡面也有paoding-rose 其它方面的介紹

國人罕見的開源項目, 用着也很不錯。 祝願其團隊日益強大、此項目風靡國内外。

-----------------------

補充些東西:

portal 的真正意義在于, 在一個頁面上如果一個子產品down 掉,其它子產品還能正常使用。

如人人網的使用者個性首頁,“使用者評論” 子產品出現異常,在之前的伺服器架構上則會導緻整個頁面出現異常(因為是由一個controller處理的請求) 。 可能有人說 我用ajax。可以。但ajax是一個頁面的多個子產品同時向伺服器發了多個請求。為伺服器增壓。而且完全用js 控制頁面,也會出現很多不相容問題。

現在最好的解決方案問世:rose 的portal  整個請求由一個控制器來處理并由這個控制器分發給每個window 的控制器。這些大家都能了解。但關鍵點在于它的意義。 就在于 portal 的 home 方法的逾時配置:@PortalSetting(timeout = 100)

和 并發配置:

        <context-param> 
                <param-name>portalExecutorCorePoolSize</param-name> 
                <param-value>200</param-value> 
        </context-param>      

沒有逾時配置的話,一個視窗逾時,controller會永遠等待這個視窗,而不傳回頁面。 沒有并發配置的話  預設一個線程處理controller 的轉發 會導緻如果前面的window 挂掉,會一直在這個window處于等待狀态,而其後面的window也就不會處理。雖然傳回了頁面  但挂掉的window 後面的所有window 也不會顯示。

以上代碼為本人初次測試的代碼,後來又做了新一步測試,實作了逾時的視窗不顯示而其他視窗正常。

代碼不想再一點點上貼,直接發個包兒吧  見附件。 項目用maven 建構 java代碼和配置檔案分别放在src/main/java 和src/main/resources web檔案放在src/main/webapp 。 如果需要項目依賴的jar email我 : [email protected]