OSGi環境下建立Web工程的Hello World

有了osgi下建立hello world的基礎,再來講搭建Web環境,會相對容易一些。一般來說,有兩種建立Web環境的方式:將HTTP服務器嵌入OSGi框架和將OSGi框架嵌入Servlet容器。

HTTP服務器嵌入OSGi框架

首先,除了下載Equinox框架,還要去下載下列這些bundle:(需要注意其版本)

  • javax.servlet
  • org.apache.commons.logging
  • org.eclipse.equinox.http.jetty
  • org.eclipse.equinox.http.servlet
  • org.eclipse.osgi.services
  • org.mortbay.jetty.server
  • org.mortbay.jetty.util

本人下載的jar包版本截圖如下:

http://assets.osgi.com.cn/article/7289380/1.jpg

這些jar包可以在我的下載裏面下:OSGI中包含web服務器配置需要的jar.zip


其中org.eclipse.osgi_3.7.0.v20110613.jar是Equinox框架的Jar包。然後在Eclipse的Window->Preferences->Plug-in Development->Target Platform中,將以上的Jar放置在New Target之中,並選中它作爲運行平臺,如下圖所示:

http://assets.osgi.com.cn/article/7289380/2.jpg

經過上面,步驟,基本搭建好Web的運行環境。然後在Run->Run Configurations中,OSGi Framwork下新建一個運行實例,選中剛剛加載進來的搜有Bundle,點擊Run,如圖所示:

http://assets.osgi.com.cn/article/7289380/3.jpg

如果沒有異常,運行效果如下(ss命令是本人額外輸入的):

http://assets.osgi.com.cn/article/7289380/4.jpg

下面,我描述下簡單寫的一個Web應用,前端一個Form表單,後臺使用Servlet簡單處理。參照“OSGi開發環境建立和Hello World”,建立OSGi工程。在Manifest.MF文件中,加入幾個Imported Packges:

http://assets.osgi.com.cn/article/7289380/5.jpg

上圖左邊是項目結構圖,右邊是Manifest.MF文件中引入的包。先看一下WeatherSerlvet的代碼,很簡單,就根據前端傳來的城市名字,返回天氣情況:

public class WeatherServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

private BundleContext context;

public WeatherServlet(BundleContext context) {
    this.context = context;
}

public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws IOException {
    doGet(request, response);
}


public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException {        

    String queryWord = request.getParameter("query_word");
    response.setContentType("text/html");
    ServletOutputStream output = response.getOutputStream();


    try {
        output.println("Result is " + queryWeather(queryWord));
        output.close();
        return;
    } catch (Exception e) {
        output.println("Error occurs");
        output.println(e.toString());
        output.close();
        return;
    }
}

private String queryWeather(String city) {

    if(city.equals("SZ"))
        return "cool";
    return "hot";
}

}

然後再看一下Activator的代碼:

public class Activator implements BundleActivator, ServiceListener {
private BundleContext bundleContext;

private ServiceReference ref;

private Servlet servlet;

public void start(BundleContext context) throws Exception {
    bundleContext = context;

    servlet = new WeatherServlet(bundleContext);

    registerServlet();

    context.addServiceListener(this, "(objectClass=" + HttpService.class.getName() + ")");
}

public void stop(BundleContext context) throws Exception {
    try {           
        unregisterServlet();
    } catch (Throwable t) {
        t.printStackTrace();
    }

    servlet = null;
    bundleContext = null;
    ref = null;
}

public void serviceChanged(ServiceEvent event) {
    switch (event.getType()){
                      case ServiceEvent.REGISTERED:             
                              registerServlet();
                              break;

                     case ServiceEvent.UNREGISTERING:               
                             unregisterServlet();
                             break;
          }
}

private void registerServlet(){
        if (ref == null){
                          ref = bundleContext.getServiceReference(HttpService.class.getName());
               }

        if (ref != null){
            try {
                     HttpService http = (HttpService) bundleContext.getService(ref);
                     if(null != http){
                
                http.registerServlet("/osgicn/index", servlet, null, null);

                http.registerResources("/osgicn/page","page",null);
                System.out.println("Html頁面已經註冊,可以訪問了!");
                      }
               } 
        catch (Exception e) {
        e.printStackTrace();
        }
        }
}

/*
 * 卸載Web應用
 */
private void unregisterServlet(){
    if (ref != null) {
        try {
            HttpService http = (HttpService) bundleContext.getService(ref);
            if(null != http){
                http.unregister("/osgicn/index");
                http.unregister("/osgicn/page");                    
            }
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
}

}

與一般的Bundle代碼不同的是,這裏需要將Html與Servlet資源註冊。對應這兩行代碼:

http.registerServlet("/osgicn/index", servlet, null, null);

http.registerResources("/osgicn/page","page",null);

第一句是註冊servlet,第二句是將page目錄下的靜態資源映射到/osgicn/page的URL空間之下。在瀏覽器中,輸入http://localhost/osgicn/page/index.html,可以看到這樣的頁面:

http://assets.osgi.com.cn/article/7289380/6.jpg

輸入SZ,可以看到結果cool,輸入其他的結果爲hot。

http://assets.osgi.com.cn/article/7289380/7.jpg

在Equinox官網,提供了另外一種註冊資源的方式,需要加入 org.eclipse.equinox.http.registry到Target Platform,然後將資源的映射關係寫在XML文件中。其實這兩種方法沒有什麼本質區別,只是將映射關係的硬編碼換成了XML配置文件。具體可以參見這裏以上工程對應代碼,我已經上傳CSDN GitHub

OSGi框架嵌入Servlet容器

在Equinox官網的示例,參見blog。我這裏講的是另一種方式,將OSGi的Web Bundle部署到Virgo容器,也屬於OSGi框架嵌入Servlet容器的範疇。爲什麼不介紹官網的方式,而是介紹部署到Virgo的方式?第一,我們一直使用這種方式開發Web應用,很熟悉Virgo;第二,這種方式已經有了對Web企業級開發的支持;第三,入門相對簡單,也對我們社區之後陸續介紹Web企業及框架起鋪墊作用。首先,在該網址,下載Virgo的zip包。我們使用的是3.5版本的,點擊下載即可,如下圖:

http://assets.osgi.com.cn/article/7289380/2_1.png

關於Virgo的介紹,可以參見Virgo簡介。然後,我們在項目中使用了Maven,所以最好配置一下,方便管理依賴和編譯工程。關於安裝Maven和Maven的Eclipse插件這裏就不多說,網上很多教程,相對簡單。當然,不使用Maven也可以,在這裏,只是下載管理依賴包麻煩一些。然後是一些依賴包,下面列出常用的,均放置到Virgo的repository/usr目錄下,如下:

http://assets.osgi.com.cn/article/7289380/2_2.jpg

這些Jar包,在我們demo中,用到的很少,我也偷一次懶,將我們項目所用的所有包都扔上來。(在開發時候,很多jar包都會用到)與基礎的Hello World教程一樣,需要下載eclipse,最好較新的版本。然後安裝Virgo的Eclipse插件——Eclipse Virgo Tools,安裝插件的update site爲:http://download.eclipse.org/virgo/release/tooling。我們新建工程是使用Maven的Archetype插件,這樣可以快速生成項目骨架。可以參見社區的另一篇文章。按照該文章,我們可以建立如下的demo工程。(如果不想安裝插件,可以直接下載我們的代碼,import到Eclipse即可。)

http://assets.osgi.com.cn/article/7289380/3.jpg

在XML文件中做好Spring MVC的配置,我給的示例是使用Spring MVC的轉發請求功能,在HomeController裏面:

public class HomeController {

public static final Logger logger = LoggerFactory.getLogger(HomeController.class);

@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model) {
    
    return "Index";
}

@RequestMapping(value = "/Target", method = RequestMethod.GET)
public String transfer(Model model) {
    
    return "Target";
}

}

訪問localhost:8080,會跳轉到Index.jsp,在Index.jsp點擊/Target鏈接,Controller會將請求跳轉到Target.jsp。

http://assets.osgi.com.cn/article/7289380/2_4.jpg

http://assets.osgi.com.cn/article/7289380/2_5.jpg

以上的跳轉是經過Spring MVC的dispatcher Servlet攔截轉發的,在OSGi環境能夠引入Spring MVC,可以極大地方便開發者搭建企業級Web系統。

對上面的樣例,做一些簡單說明:1.這個工程展示的是將Web邏輯全部放在一個Bundle之中,OSGi支持多個Web Bundle構建成一個Web應用。多個Web Bundle的時候,需要引入Virgo Snaps。關於Snaps的介紹可以參見這篇文章

2.本文的第二部分,讀者可以看出,已經引入了Spring,在此基礎之上,再嵌入數據層,一個開發框架的原型已經出來了。我們之後會很詳細地介紹本小組使用的框架,歡迎關注。

3.本文設計代碼已經放在GitHub 關於文中提到的依賴jar,也全部放在GitHub

由於涉及到很多配置,如Maven、Virgo插件等,加上本人水平有限,讀者有可能會遇到不少一些問題。可以在本文留言。



發佈了0 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章