程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用Felix和Struts2開發Web應用

使用Felix和Struts2開發Web應用

編輯:關於JAVA

簡介: 本文首先對 OSGi 和 Felix 進行了簡要的介紹,然後通過一個示例詳 細描述了如何使用 Felix 和 Struts 開發 Web 應用,同時演示了 OSGi 的模塊 化及動態部署特性。隨後,講解了 OSGi bundles 管理常用的命令操作,以及在 開發過程中的幾個常見的問題的解決方法。

引言

Open Service Gateway Initiative(OSGi) 是一個針對 Java 動態模塊開發的 規范。基於中間件的 OSGi 技術提供了一個面向服務,基於組件的開發環境,並 提供標准化的方式來管理整個軟件生命周期。OSGi 為那些需要長時間運行,動態 更新並且對運行環境的影響盡可能小的系統提供了很好的支持。基於 OSGi 開發 的系統具有復雜度低、可重用、動態部署、可持續運行、開發簡單等特點。

OSGi 技術結合了上述特點的各方面來定義一個動態服務部署框架,可以進行 遠程管理。OSGi 技術起初只是關注於嵌入式領域,諸如機頂盒、服務網關、手機 等應用環境。但是它完美地適用在任一模塊化、面向組件、面向服務的項目。 Eclipse V3.0 以後采用 OSGi 作為其模塊化和動態化平台,設計了 Equinox 內 核,使用 OSGi 技術幫助其進行類載入,大大提升了 Eclipse 的啟動速度。在應 用服務器上,WebSphere,Weblogic,JBOSS 等著名的服務器都支持或使用了 OSGi 技術。

Felix 是一個 Apache 旗下 OSGi 實現的開源框架,它的最終的目標是提供一 個完全兼容的 OSGi 框架和標准服務的實現。Felix 當前實現了 OSGi 規范 4 的 大部分內容,目前 Felix 提供的 OSGi 框架功能是非常穩定的。

采用 Spring DM 和 Jetty 等 Web 容器開發基於 OSGi 的 Web 應用的方法已 經在很多書本或技術文章上提及。但是這種開發方法與傳統的 Web 開發差別較大 ,開發人員很難轉換到這種開發模式上,並且它的穩定性也沒有得到充分的驗證 。

很多 Web 開發都采用 Struts 作為其控制層,很幸運的是,最新發布的 Struts2.1.8.1 中,加入了對 Felix OSGi 的支持,能夠在傳統的 Web 開發中集 成 OSGi 的模塊管理平台,而且開發方法沒有太大的改變,開發後的應用程序仍 像原先一樣可以方便的部署在 Tomcat,JBoss 等容器上。

本文將通過下面的示例,詳細講述如何使用 Felix 和 Struts 開發 Web 應用 。

使用 Felix 和 Struts 開發 Web 應用示例

下面講解的示例是一個獲取時間信息並在 Web 浏覽器中顯示的簡單示例,該 示例主要介紹了怎樣使用 Felix 和 Struts 結合起來開發 Web 應用。該示例中 有兩個獲取時間信息的 bundle,這兩個 bundle 實現同一個接口服務,但是有不 同的實現,這兩個 bundle 可以在應用中動態部署。通過該示例,可以體現出基 於 OSGi 開發的項目具有良好的模塊化以及 OSGi 的 bundle 動態部署的能力, 從而說明了 OSGi 適用於開發持續運行且需要動態更新的系統。

在這個示例中,一共包括五個工程,一個 Web Application 工程和四個 OSGi bundle 工程。Web Application 工程是用於 Web 部署。四個 OSGi bundle 中, 包括一個 Web bundle,用於 Web 交互;一個 time service bundle,包含一個 獲取時間信息的接口服務;一個 local time service bundle,實現接口服務, 用於獲取本地時間信息;一個 utc time service bundle,用於獲取世界標准時 間(Universal Time Coordinated,UTC)信息。

本示例的結構原理如圖 1 所示。在 Web Container 中注冊了 Struts OSGi 的監聽器,該監聽器會去啟動或停止 Apache Felix Host,Apache Felix Host 是 Struts OSGi Plugin 和 Felix Framework 的連接點。Felix Host 會去創建 和初始化 Felix Framework,Felix Framework 負責管理系統中的其余的所有 bundle,Struts OSGi Plugin 會監聽 bundle 的變化,如果發生變化的 bundle 是一個 Struts bundle, 則會去加載 Struts 的配置。

圖 1. 示例結構原理圖

建立 OSGi 的 Web 開發環境

本文示例使用的 Web 開發環境包括如下組件:

Eclipse 3.5 for Java EE Developers

Sun JDK 1.6.0

Tomcat 6.0.24

Struts 2.1.8.1 (Essential Dependencies Only)

spring-osgi-1.1.2-with-dependencies (Only Need when adding Spring Support)

Web Application 工程的創建方式與通常的 Web 工程類似,但是需要加入 Felix 的支持和 Struts2 OSGi Plugin. Felix 是 OSGi 的平台,用於管理整個 系統中的所有的 bundle,而 Struts2 OSGi Plugin 是 Struts2 和 OSGi 連接的 橋梁,通過 Struts2 OSGi Plugin 將 Felix 融入到 Struts2 框架中。另外,還 需要加入 Struts2 OSGi Admin bundle,這個 bundle 向管理人員提供基於 Web 的管理 OSGi 平台中的 bundle 的操作入口。同時在 web.xml 中需要加入 Struts OSGi 監聽器,這樣 OSGi 平台中的 bundle 發生變化時,會觸發該監聽 器去做一些與 Struts 相關測操作,例如增加 Action 或使 Action 失效。

web.xml 中過濾器和監聽器部分的配置內容如清單 1:

清單 1. web.xml 過濾器和監聽器配置

<filter>
   <filter-name>struts2-prepare</filter-name>
  <filter- class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter< ;/filter-class>
  </filter>
  <filter>
  <filter-name>struts2-execute</filter-name>
   <filter- class>org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter
   </filter-class>
  </filter>

  <filter-mapping>
   <filter-name>struts2-prepare</filter-name>
   <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter-mapping>
   <filter-name>struts2-execute</filter-name>
   <url-pattern>/*</url-pattern>
  </filter-mapping>
  <listener>
   <listener- class>org.apache.struts2.osgi.StrutsOsgiListener</listener- class>
  </listener>
  <listener>
   <listener- class>org.apache.struts2.dispatcher.ng.listener.StrutsListener
   </listener-class>
  </listener>

Web Application 工程的目錄結構如圖 2 所示:

圖 2. Web Application 工程的目錄結構

將 Web Application 部署到 Tomcat 上並啟動 Tomcat,然後在浏覽器中輸入 http://localhost:8080/webapp/osgi/admin/bundles.action, (webapp 是項目 部署到 Tomcat 中的名字 ) 如果看到了類似於 圖 5的 bundles 列表,說明 OSGi 環境配置成功。

開發獲取時間消息接口服務 bundle

消息接口服務 bundle 是提供消息服務的接口,該接口將被 Web bundle 所使 用,其他 bundle 可以不同的形式實現該接口。在這裡利用 eclipse 新建插件工 程的功能來創建 OSGi bundle。需要特別設置 an OSGI framework 為 standard 方式,這種方式允許部署項目到標准的 OSGI 容器中。新建 OSGi 工程的向導如 圖 3 所示。

圖 3. 新建 OSGi 工程向導圖

在該項目中開發一個用於獲取時間信息的接口,通過該接口可以獲取字符串形 式的時間信息。

清單 2. 獲取時間服務接口代碼

package com.example.time.service;

  public interface TimeService{
  public String getTime();
  }

需要將該 bundle中的服務包的類和接口就暴露給了其他的 bundle,其他的 bundle可以通過 import這個包來使用其中的類和接口。

開發獲取本地時間消息實現服務 bundle

獲取本地時間消息服務 bundle 實現了時間消息接口服務。在該 bundle 種返 回的時間消息是當前時區的時間信息。因為用到了接口服務包,所以需要在 Import-Package 中加入接口服務包。

清單 3. 獲取本地時間實現代碼

package com.example.time.local.service;
  import java.text.SimpleDateFormat;
  import java.util.Calendar;
  import java.util.Date;
  import com.example.time.service.TimeService;
  public class LocalTimeService implements TimeService{
  @Override
  public String getTime(){
  Calendar calendar = Calendar.getInstance();
  Date date = calendar.getTime();
  SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss");
  return "The local time:" + formatter.format(date);
   }
  }

OSGi bundle 中的服務要能夠被其他 bundle 使用,使用將服務發布出來。在 該 bundle 的 Activator 的 start() 方法中注冊該服務,可以發布這個服務。 當這個 bundle 啟動時,將獲取本地時間發布為一個服務。服務發布的代碼如清 單 4 所示。

清單 4. 服務發布

public void start(BundleContext context) throws  Exception{
   context.registerService(TimeService.class.getName(), new  LocalTimeService(), null);
  }

開發獲取 UTC 時間消息實現服務 bundle

獲取 UTC 時間消息實現服務同樣實現了時間消息接口服務,該 bundle 主要 是用於和上一個 bundle 即獲取本地時間消息服務進行動態的替換,用於表現 OSGi 的動態部署的能力。

清單 5. 獲取 UTC 時間服務實現

public class UTCTimeService implements TimeService {
   @Override
   public String getTime() {
     Calendar calendar = Calendar.getInstance();
  int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
  int dstOffset = calendar.get(Calendar.DST_OFFSET);
  calendar.add(Calendar.MILLISECOND, -(zoneOffset +  dstOffset));
  Date date = calendar.getTime();
  SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd  HH:mm s");
  return "The UTC time:" + formatter.format(date);
   }
  }

開發 Web bundle

Web bundle 是系統 Web 交互的入口。在該 bundle 中需要使用時間消息接口 服務 bundle 中的接口,所有需要在 MANIFEST.MF 的 Import-Package 加入時間 消息接口服務包,另外,為了能夠識別出該 bundle 是一個 Struts bundle, 需 要將該 bundle 設置為可被 Struts2 支持 , 即在 MANIFEST.MF 中加入 Struts2-Enabled: true, 這樣該 bundle 中的 struts.xml 就會被加載。最終的 MANIFEST.MF 的配置如清單 6。

清單 6. Web Bundle 的 MANIFEST.MF 配置

Manifest-Version: 1.0
  Bundle-ManifestVersion: 2
  Bundle-Name: com-example-time-web
  Bundle-SymbolicName: com.example.time.web
  Bundle-Version: 1.0.0.qualifier
  Bundle-Vendor: keki
  Bundle-RequiredExecutionEnvironment: JavaSE-1.6
  Struts2-Enabled: true
  Import-Package: com.example.time.service,
  com.opensymphony.xwork2,
  org.apache.struts2.osgi.interceptor,
  org.osgi.framework;version="1.3.0"

為了實現用戶交互,還需要創建一個獲取時間消息響應的 action。該 Action 的 execute() 方法代碼如清單 7 所示。

清單 7. Action 實現方法

public String execute(){
   ServiceReference ref = bundleContext.getServiceReference (
   TimeService.class.getName());
   TimeService timeService = (TimeService)  bundleContext.getService(ref);
   timeMessage = timeService.getTime();
   return SUCCESS;
  }

這個 Web bundle 中獨立的建立一個 struts.xml,這個 struts.xml 將會為 單獨加載,需要注意的是 Struts 的 pacakge 繼承 osgi-default 這個包, osgi-default 已在 struts2-osgi-plugin 這個 jar 包裡面定義。

清單 8. Web Bundle struts.xml 的 action 定義

<struts>
   <package name="time-example" namespace="/time" extends="osgi- default">
     <action name="time"  class="com.example.time.web.action.TimeAction">
       <result type="freemarker">time.ftl</result>
     </action>
   </package>
  </struts>

打包部署

將開發好的四個 bundle 導出成 plugin 的包,並將它們放在 Web App 工程 中 ,bundles 的目錄結構如圖 4 所示。

圖 4. Web Application 中的 bundles 目錄結構

運行演示

啟動 Tomcat,在浏覽器地址欄輸入 http://localhost:8080/webapp/osgi/admin/bundles.do, 可以看到所系統中所 有的 bundle 的列表。

圖 5. 部署的 bundles 列表

在浏覽器地址欄輸入 http://localhost:8080/webapp/time/time.do,可以獲 得時間信息,此時的時間信息為本地時間信息,當前 TimeService 這個服務有 local time service 和 UTC time service 兩個實現,調用的是 local time service 這個實現。

圖 6. 獲取本地時間頁面顯示

此時,在浏覽器地址欄輸入 http://localhost:8080/webapp/osgi/admin/shell.do,然後輸入命令 stop 1, 將 Local time service 這個 bundle 停止掉,輸入命令 ps, 可以看到 local time service 這個 bundle 的 state 已經變為 Resolved.

圖 7. OSGi Shell 管理頁面

在浏覽器地址欄再次輸入 http://localhost:8080/webapp/time/time.do 得 到的結果如圖 7 所示。

圖 8. 獲取 UTC 時間顯示頁面

通過上面的演示,我們可以看到 OSGi bundle 的動態部署能力。

bundle 的管理

通過 Felix 可以方便的管理項目中的 bundle,並且實現 bundle 的熱部署, 即插即用,即刪即無的特性,特別適用於可持續運行的系統。

添加 bundle

輸入命令 install <bundle-url>,然後輸入 start <bundle- id> 即可。如 $install file:/k:/plugins/com.example.time.local_1.0.0.qualifier.jar , $start 7

更新 bundle

輸入命令 update <bundle-id> <bundle-url> 即可。如

$ update 1 file:/k:/plugins/com.example.time.local_1.0.0.qualifier.jar

啟動和停止 bundle

輸入命令 start <bundle-id> 啟動 bundle;輸入命令 stop <bundle-id> 停止 bundle。如

$ start 2 , $ stop 1

卸載 bundle

若 bundle 處於 Installed 或 Resolve 狀態,則直接輸入命令 uninstall <bundle-id>。若 bundle 處於 Actived 狀態,則先輸入命令 stop <bundle-id> 停止 bundle, 再輸入命令 uninstall <bundle-id>。 如 $ uninstall 1

常見問題

如何修改 bundle 的最大啟動級別

在上面的示例中,bundle 中最大的啟動級別只能為 3。如果在 bundles 下面 增加一個目錄 4,即 bundles/4,則目錄 4 中的 bundle 是無法啟動的,而在很 多時候,特別是在大型的項目中,最大啟動級別為 3 是不能滿足要求,此時可以 web.xml 中添加啟動級別的參數。如下面把最大啟動級別設置為 5。

清單 9. 啟動級別配置

<context-param>
   <param-name>struts.osgi.runLevel</param-name>
   <param-value>5</param-value>
  </context-param>

解決 Bundle 中的 struts.xml 的 Struts Configuration DTD 無法定位的問 題

Struts.xml 的頭部有 Struts Configuration DTD 的引用定義,一般 DTD 文 檔的 URL 為 http://struts.apache.org/dtds/XXX.dtd ,示例如下所示:

清單 10. struts.xml 頭部 dtd

<!DOCTYPE struts PUBLIC "-//Apache Software  Foundation//DTD Struts 
  Configuration 2.0//EN" 
"http://struts.apache.org/dtds/struts-2.0.dtd">

如果無法連接上 http://struts.apache.org/,那麼在加載 Struts 的 bundle 時也將會出錯,因為 bundle 與 Web Application 的 lib 的加載路徑不 一致,無法從 Web Application 的 lib 下面找到 XXX.dtd 文件。此時可以通過 修改 dtd 文件的 URL 來解決,可以改成一個本地文件系統的 URI,如 file:/c:/webapp/dtds/struts-2.0.dtd,也可以改為本地的 Web 服務器或一個 可以連接上的服務器的 URL,如 http://localhost/dtds/struts-2.0.dtd。

如何使用 Spring 進行對象管理

Spring DM 使得 Spring 和 OSGi 成為可能,在本文的開發環境中,也可以加 入 Spring DM 來管理系統中的對象。首先加入 Spring DM 必要的 jar 包,如

清單 11. Spring 依賴包示例

com.springsource.org.aopalliance-1.0.0.jar,
  com.springsource.org.apache.commons.logging-1.1.1.jar,
  spring-aop-2.5.5.jar,
  spring-beans-2.5.5.jar,
  spring-context-support-2.5.5.jar,
  spring-core-2.5.5.jar,
  spring-osgi-core-1.1.2.jar,
  spring-osgi-extender-1.1.2.jar,
  spring-osgi-is-1.1.2.jar,
  spring-osgi-web-1.1.2.jar,
  spring-osgi-web-extender-1.1.2.jar,
  spring-web-2.5.5.jar

然後需要在 Web Application 的 struts.xml 中加入對象工廠的配置,配置 如下:

清單 12. 配置對象工廠

<constant name="struts.objectFactory"  value="osgi" />
  <constant name="struts.objectFactory.delegate" value="springOsgi"  />

在 Web Application 的 web.xml 加入 Spring 的監聽器 , 配置如下:

清單 13. 配置 Spring 監聽器

<listener>
   <listener- class>org.springframework.web.context.ContextLoaderListener
   </listener-class>
  </listener>
  <context-param>
   <param-name>contextClass</param-name>
   <param-value>
  org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicatio nContext 
  </param-value>
  </context-param>
  <context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>osgibundle:/META-INF/spring/*.xml,/spring/*.xml  </param-value>
  </context-param>
  <context-param>
   <param-name>parentContextKey</param-name>
   <param-value>parent-context-bean</param-value>
  </context-param>

在 OSGi bundle 中,如果需要用 Spring 來管理對象,則把 Spring 對象的 配置文件放在 /META-INF/spring/ 目錄下面,並以 xml 為擴展名即可。Spring 對象配置文件的寫法在很多 Spring DM 的書籍或文章中都有講解,這裡不再重復 。最後需要在 MANIFEST.MF 中加入如下聲明用來配置 Spring 上下文和對象創建 機制,create-asynchronously 的值為 true 表示可以允許異步創建對象。

清單 14. 配置 Spring 對象創建方式

Spring-Context: *;create-asynchronously:=true

小結

本文首先對 OSGi 和 Felix 進行了簡要的介紹,然後通過一個示例詳細介紹 了使用 Felix 和 Struts 開發 Web 應用,演示了 OSGi 的動態部署特性。隨後 ,講解了 OSGi bundles 管理常用的命令操作,以及在開發過程中的幾個常見的 問題的解決方法。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved