首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

整合 Felix 與 Struts 2 開發模組化 Web 應用:實踐 OSGi 動態部署

     編輯:Java 相關知識

前言:OSGi 與 Felix 簡介

OSGi(Open Service Gateway Initiative)是針對 Java 動態模組開發的規範,提供面向服務、基於元件的開發環境,標準化管理軟體全生命週期。OSGi 適合需長時間運行、動態更新且對環境影響最小的系統,特點包括低複雜度、高可重用、動態部署、持續運行、開發簡單。

Felix 是 Apache 旗下的 OSGi 開源實作,目標是提供完全相容的 OSGi 框架與標準服務實作,目前功能穩定。雖然 Spring DM + Jetty 等方案已有介紹,但與傳統 Web 開發差異大,轉換困難且穩定性待驗證。幸運的是,Struts 2.1.8.1 加入 Felix OSGi 支援,讓傳統 Web 開發能整合 OSGi 模組管理平台,開發模式幾乎無變化,應用仍可部署於 Tomcat、JBoss 等容器。

範例架構:時間服務的動態切換

範例架構原理圖

範例包含五個工程:一個 Web Application 工程、四個 OSGi Bundle 工程:

  • Web Bundle:Web 互動入口
  • Time Service Bundle:定義取得時間資訊的介面服務
  • Local Time Service Bundle:實作介面,提供本地時間
  • UTC Time Service Bundle:實作介面,提供世界標準時間(UTC)

兩個實作 Bundle 可動態部署替換,展現 OSGi 模組化與動態部署能力。

建立 OSGi 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(需 Spring 支援時)

Web Application 關鍵配置

web.xml 需配置 Struts 2 過濾器與 OSGi 監聽器:

<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>

StrutsOsgiListener 負責啟動/停止 Apache Felix Host(Struts OSGi Plugin 與 Felix Framework 連接點),Felix Host 創建初始化 Felix Framework 管理所有 Bundle。Struts OSGi Plugin 監聽 Bundle 變化,若為 Struts Bundle 則載入其配置。

目錄結構

Web Application 目錄結構

部署至 Tomcat 啟動後,瀏覽 https://localhost:8080/webapp/osgi/admin/bundles.action 若看到 Bundle 列表(部署的 Bundles 列表)即配置成功。

開發各 Bundle 實作

1. 時間服務介面 Bundle

使用 Eclipse 新增 Plug-in 專案,設定 OSGi framework 為 standard。定義介面:

package com.example.time.service;
public interface TimeService {
    public String getTime();
}

在 MANIFEST.MF 的 Export-Package 暴露此套件供其他 Bundle 使用。

2. 本地時間服務實作 Bundle

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);
    }
}

在 Activator.start() 發布服務:

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

Import-Package 引入介面服務套件。

3. UTC 時間服務實作 Bundle

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:ss");
        return "The UTC time:" + formatter.format(date);
    }
}

同樣在 Activator 發布服務,用於動態替換本地時間服務。

4. Web Bundle(Struts 整合)

MANIFEST.MF 關鍵配置:

Manifest-Version: 1.0
Bundle-SymbolicName: com.example.time.web
Struts2-Enabled: true
Import-Package: com.example.time.service,
 com.opensymphony.xwork2,
 org.apache.struts2.osgi.interceptor,
 org.osgi.framework;version="1.3.0"

Struts2-Enabled: true 標識此為 Struts Bundle,其 struts.xml 會被獨立載入。

Action 實作:

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

struts.xml(繼承 osgi-default 套件):

<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 目錄(Bundles 目錄結構)。

演示動態部署

  1. 瀏覽 https://localhost:8080/webapp/time/time.do → 顯示本地時間(本地時間頁面)
  2. 進入 OSGi Shell(https://localhost:8080/webapp/osgi/admin/shell.do),執行 stop 1 停止 Local Time Service Bundle,ps 確認狀態變為 Resolved(OSGi Shell 管理頁面)
  3. 再次瀏覽 /time/time.do → 顯示 UTC 時間(UTC 時間頁面)

此過程展示 OSGi Bundle 動態部署能力:無需重啟應用即可熱替換服務實作。

Bundle 管理常用命令

操作命令範例
安裝install <bundle-url> 後 start <bundle-id>install file:/k:/plugins/...jar, start 7
更新update <bundle-id> <bundle-url>update 1 file:/k:/plugins/...jar
啟動/停止start/stop <bundle-id>start 2, stop 1
卸載Installed/Resolved 狀態:uninstall <id>;Active 狀態:先 stop 再 uninstalluninstall 1

常見問題解決

1. 修改 Bundle 最大啟動層級

預設最大層級為 3。在 web.xml 新增:

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

2. 解決 struts.xml DTD 無法定位

若無法連接 https://struts.apache.org/,修改 DTD URL 為本地或可連線位址:

<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 
  "file:/c:/webapp/dtds/struts-2.0.dtd">

3. 整合 Spring 管理物件

加入 Spring DM 相關 JAR(spring-osgi-core, spring-osgi-extender 等),在 struts.xml 配置物件工廠:

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

web.xml 加入 Spring 監聽器與上下文配置,Bundle 中 Spring 配置放於 /META-INF/spring/*.xml,MANIFEST.MF 加入:

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

小結

本文透過完整範例展示 Felix + Struts 2 整合開發 OSGi Web 應用,演示動態部署特性,並說明 Bundle 管理命令與常見問題解決方案,為傳統 Web 開發引入 OSGi 模組化能力提供實用參考。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved