日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

使用 Equinox 开发 OSGi 应用程序

發(fā)布時(shí)間:2025/3/21 编程问答 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用 Equinox 开发 OSGi 应用程序 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

開(kāi)始之前

關(guān)于本教程

OSGi 是目前動(dòng)態(tài)模塊系統(tǒng)的事實(shí)上的工業(yè)標(biāo)準(zhǔn),雖然一開(kāi)始只是作為嵌入式設(shè)備和家庭網(wǎng)關(guān)的框架來(lái)使用,但是實(shí)際上它適用于任何需要模塊化、面向服務(wù)、面向組件的應(yīng)用程序。而 Equinox 則是的 Eclipse 所使用的 OSGi 框架,是 Eclipse 強(qiáng)大的插件體系的基礎(chǔ),Eclipse 的穩(wěn)定可靠性也為該框架帶來(lái)了聲譽(yù)。

本教程就將演示如何在 Eclipse 環(huán)境下利用 Equinox 框架進(jìn)行 OSGi 應(yīng)用開(kāi)發(fā)。首先解釋了實(shí)現(xiàn)上述應(yīng)用程序所必需了解的基本概念和基礎(chǔ)知識(shí),并結(jié)合示例代碼演示 OSGi 開(kāi)發(fā)的一些重要技術(shù),最后探討了基于 OSGi 應(yīng)用程序一般所采用的架構(gòu),以及如何將 Equinox OSGi 應(yīng)用程序脫離 Eclipse 而部署為一個(gè)標(biāo)準(zhǔn)的 Java 應(yīng)用程序。

目標(biāo)

在本教程中,您將學(xué)習(xí):

  • OSGi 及框架簡(jiǎn)介
  • 編寫(xiě)第一個(gè) OSGi 應(yīng)用程序
  • 重要的理論知識(shí)
  • 開(kāi)發(fā)一個(gè)真實(shí)的 OSGi 應(yīng)用程序
  • 探討 OSGi 應(yīng)用架構(gòu)
  • 部署 OSGi 應(yīng)用程序

先決條件

本教程假設(shè)讀者熟悉基本 Java 語(yǔ)言以及 Eclipse 開(kāi)發(fā)環(huán)境的使用。

系統(tǒng)需求

本教程假設(shè)您有一個(gè)可以工作的 Eclipse 3.x 環(huán)境。如果還沒(méi)有,請(qǐng)?jiān)?Eclipse 網(wǎng)站?上找到相關(guān)下載的鏈接,以幫助您在自己的系統(tǒng)上操作示例步驟以及運(yùn)行示例代碼。

OSGi 及框架簡(jiǎn)介

OSGi 簡(jiǎn)介

OSGi 是目前動(dòng)態(tài)模塊系統(tǒng)的事實(shí)上的工業(yè)標(biāo)準(zhǔn),雖然一開(kāi)始只是作為嵌入式設(shè)備和家庭網(wǎng)關(guān)的框架來(lái)使用,但是實(shí)際上它適用于任何需要模塊化、面向服務(wù)、面向組件的應(yīng)用程序。

目前 OSGi 規(guī)范已經(jīng)發(fā)展到第四版(R4), 由 OSGi 聯(lián)合組織(OSGi Alliance)負(fù)責(zé)進(jìn)行維護(hù)管理,相關(guān)的規(guī)范資料也可以從該網(wǎng)站獲得。(參考資料)

OSGi 框架

開(kāi)發(fā)基于 OSGi 的應(yīng)用程序離不開(kāi)實(shí)現(xiàn)了 OSGi 標(biāo)準(zhǔn)的框架,就好比是基于 J2EE 的開(kāi)發(fā)離不開(kāi)應(yīng)用服務(wù)器一樣。目前比較流行的基于 OSGi R4 標(biāo)準(zhǔn)實(shí)現(xiàn)的 OSGi 框架有三個(gè):

  • Equinox:這是大名鼎鼎的 Eclipse 所使用的 OSGi 框架,Eclipse 強(qiáng)大的插件體系就是構(gòu)建在 OSGi bundles 的基礎(chǔ)之上,Eclipse 的穩(wěn)定可靠性為該框架帶來(lái)了聲譽(yù),而且由于有 IBM 公司的強(qiáng)力支持,其后續(xù)的開(kāi)發(fā)和文檔資料也有了一定的保障。一般情況下,我們推薦您使用該框架進(jìn)行 OSGi 開(kāi)發(fā)。本教程的后續(xù)部分也將演示如何使用 Equinox 框架來(lái)進(jìn)行 OSGi 應(yīng)用程序的開(kāi)發(fā)。

  • Makewave Knopflerfish:這是另外一個(gè)比較知名的 OSGi 框架,目前的版本已經(jīng)支持 R4 規(guī)范,其特點(diǎn)在于為應(yīng)用程序的開(kāi)發(fā)提供了大量的 bundle 。

  • Apache Flex:由 Apache 基金組織開(kāi)發(fā)的面向社區(qū)的 OSGi 框架實(shí)現(xiàn),提供了標(biāo)準(zhǔn)的服務(wù)和一些有趣的和 OSGi 相關(guān)的服務(wù)實(shí)現(xiàn)。

  • Hello World!編寫(xiě)第一個(gè) OSGi 應(yīng)用程序

    準(zhǔn)備工作

  • 從附屬資料中下載 Eclipse 3.x 版本,Eclipse 3.2+ 版本已經(jīng)全面支持 OSGi R4 規(guī)范。目前最佳實(shí)踐是下載 Eclipse 3.3.2 版本。(下載請(qǐng)見(jiàn):參考資料)
  • 將 Eclipse 解壓縮到 d:\work\seclipse 目錄,開(kāi)始我們的 OSGi 之旅。
  • Hello World

    一般情況下,學(xué)習(xí)一門(mén)新的技術(shù),程序員都習(xí)慣于首先開(kāi)發(fā)一個(gè) hello world 應(yīng)用程序,這似乎也是一種“工業(yè)標(biāo)準(zhǔn)”。好的,讓我們開(kāi)始吧,開(kāi)發(fā)一個(gè)簡(jiǎn)單的 OSGi 應(yīng)用程序并不難,步驟如下:

  • 建立一個(gè) plug-in 工程,File > New > Project,選擇?Plug-in development > Plug-in Project

    圖 1. 新建 plug-in 工程

  • 在建立工程的第一個(gè)向?qū)?#xff0c;填入工程的名稱(chēng):osgi.test.helloworld,使用缺省的工程路徑。注意目標(biāo)平臺(tái)的選擇,由于我們的項(xiàng)目是一個(gè)通用的 OSGi bundle,所以選擇?equinox?。

    圖 2. 填入工程名及選擇目標(biāo)平臺(tái)

  • 在下一個(gè)向?qū)Ы缑嬷?#xff0c;填入需要的一些插件信息(注意 Eclipse 中的插件概念基本類(lèi)似于 OSGi 中的 bundle 的概念),這里需要填入的是 OSGi 的 provider(供應(yīng)商)和 classpath 。如果沒(méi)有特別的設(shè)計(jì),一般可以忽略這兩個(gè)字段 。最后是關(guān)于 activator 的部分,如果不是一個(gè) fragment bundle 則需要填入,除非您的 bundle 自己實(shí)現(xiàn)框架的事件監(jiān)聽(tīng),這個(gè)似乎也沒(méi)有必要。因此,建議使用缺省的設(shè)置,如圖 3:

    圖 3. 使用缺省設(shè)置

    Activator:這是 bundle 啟動(dòng)時(shí)首先調(diào)用的程序入口,相當(dāng)于 Java 模塊中的 main 函數(shù)。不同的是,main 需要通過(guò)命令行調(diào)用,而 OSGi 的 Activator 是被動(dòng)的接受 OSGi 框架的調(diào)用,收到消息后才開(kāi)始啟動(dòng)。

    最佳實(shí)踐:不要在 Activator 中寫(xiě)太多的啟動(dòng)代碼,否則會(huì)影響 bundle 啟動(dòng)速度,相關(guān)的服務(wù)啟動(dòng)可以放到服務(wù)的監(jiān)聽(tīng)器中。

  • 最后一步,不使用任何的模板,所以勾掉缺省的選項(xiàng),點(diǎn)擊完成,如圖 4:

    圖 4. 勾掉缺省的選項(xiàng)

  • 完成,基本的插件視圖如圖 5,Eclipse 會(huì)在工程名下建立相同路徑的 Java Package,其中包含了 Activator 類(lèi),插件的配置信息也都放在 MANIFEST.MF 文件中,將來(lái)我們相當(dāng)多的工作都是在其中完成。

    圖 5. 基本的插件視圖

  • 編輯 Activator.java,輸入 hello world 語(yǔ)句,代碼如下:

    清單 1. 編輯 Activator.java

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    package osgi.test.helloworld;

    ?

    import org.osgi.framework.BundleActivator;

    import org.osgi.framework.BundleContext;

    ?

    public class Activator implements BundleActivator {

    ?

    ?????/*

    ?????* (non-Javadoc)

    ?????* @see org.osgi.framework.BundleActivator

    ?????*???? #start(org.osgi.framework.BundleContext)

    ?????*/

    ?????public void start(BundleContext context) throws Exception {

    ????????System.out.println("hello world");

    ?????}

    ?

    ?????/*

    ?????* (non-Javadoc)

    ?????* @see org.osgi.framework.BundleActivator

    ?????*???? #stop(org.osgi.framework.BundleContext)

    ?????*/

    ?????public void stop(BundleContext context) throws Exception {

    ?????}

    ?}

    我們可以看到每個(gè) Activator 實(shí)際都是實(shí)現(xiàn)了?BundleActivator?接口,此接口使 Activator 能夠接受框架的調(diào)用。在框架啟動(dòng)后,啟動(dòng)每個(gè) bundle 的時(shí)候都會(huì)調(diào)用每個(gè) bundle 的 Activator 。

    注意:bundle 的 Activator 必須含有無(wú)參數(shù)構(gòu)造函數(shù),這樣框架才能使用?Class.newInstance()?方式反射構(gòu)造 bundle 的 Activator 實(shí)例。

    這里我們?cè)?start?方法中填入了我們希望輸出的 hello world 字符串。那么,怎么才能啟動(dòng)這個(gè) bundle 呢?

  • 執(zhí)行:選擇?Run > Open Run Dialog,進(jìn)入運(yùn)行菜單,在 OSGi framework 中右鍵點(diǎn)擊選擇?new?一個(gè)新的 OSGi 運(yùn)行環(huán)境,如圖:

    圖 6. 新建 OSGi 運(yùn)行環(huán)境

    在右邊的運(yùn)行環(huán)境對(duì)話框中,輸入運(yùn)行環(huán)境的名字、start level 和依賴(lài)的插件,由于我們目前不需要其它的第三方插件,因此只需要勾上系統(tǒng)的 org.eclipse.osgi 插件,如果不選擇此插件,hello world 將無(wú)法運(yùn)行。如圖 7,只有當(dāng)您點(diǎn)擊了?validate bundles?按鈕 ,并且提示無(wú)問(wèn)題之后,才表明您的運(yùn)行環(huán)境基本 OK 了。

    圖 7. 選擇 org.eclipse.osgi插件

    依賴(lài)插件的選擇:

    圖 8. 依賴(lài)插件的選擇

    好的,如果您的運(yùn)行環(huán)境已經(jīng) OK,那么就點(diǎn)擊?Run?吧。

    圖 9. 運(yùn)行 OSGi 項(xiàng)目

    恭喜您,成功了!

  • OSGi 控制臺(tái)

    OSGi 控制臺(tái)對(duì)于習(xí)慣開(kāi)發(fā)普通 Java 應(yīng)用程序的開(kāi)發(fā)人員來(lái)說(shuō),還是比較新鮮的。一般來(lái)說(shuō),通過(guò) OSGi 控制臺(tái),您可以對(duì)系統(tǒng)中所有的 bundle 進(jìn)行生命周期的管理,另外也可以查看系統(tǒng)環(huán)境,啟動(dòng)、停止整個(gè)框架,設(shè)置啟動(dòng)級(jí)別等等操作。如圖 10,鍵入?SS?就可以查看所有 bundle 的狀態(tài):

    圖 10. 查看所有 bundle 的狀態(tài)

    下面列出了主要的控制臺(tái)命令:

    表 1. Equinox OSGi 主要的控制臺(tái)命令表

    類(lèi)別命令含義
    控制框架launch啟動(dòng)框架
    shutdown停止框架
    close關(guān)閉、退出框架
    exit立即退出,相當(dāng)于 System.exit
    init卸載所有 bundle(前提是已經(jīng) shutdown)
    setprop設(shè)置屬性,在運(yùn)行時(shí)進(jìn)行
    控制 bundleInstall安裝
    uninstall卸載
    Start啟動(dòng)
    Stop停止
    Refresh刷新
    Update更新
    展示狀態(tài)Status展示安裝的 bundle 和注冊(cè)的服務(wù)
    Ss展示所有 bundle 的簡(jiǎn)單狀態(tài)
    Services展示注冊(cè)服務(wù)的詳細(xì)信息
    Packages展示導(dǎo)入、導(dǎo)出包的狀態(tài)
    Bundles展示所有已經(jīng)安裝的 bundles 的狀態(tài)
    Headers展示 bundles 的頭信息,即 MANIFEST.MF 中的內(nèi)容
    Log展示 LOG 入口信息
    其它Exec在另外一個(gè)進(jìn)程中執(zhí)行一個(gè)命令(阻塞狀態(tài))
    Fork和 EXEC 不同的是不會(huì)引起阻塞
    Gc促使垃圾回收
    Getprop得到屬性,或者某個(gè)屬性
    控制啟動(dòng)級(jí)別Sl得到某個(gè) bundle 或者整個(gè)框架的 start level 信息
    Setfwsl設(shè)置框架的 start level
    Setbsl設(shè)置 bundle 的 start level
    setibsl設(shè)置初始化 bundle 的 start level

    MANIFEST.MF

    MANIFEST.MF 可能出現(xiàn)在任何包括主類(lèi)信息的 Jar 包中,一般位于 META-INF 目錄中,所以此文件并不是一個(gè) OSGi 特有的東西,而僅僅是增加了一些屬性,這樣也正好保持了 OSGi 環(huán)境和普通 Java 環(huán)境的一致性,便于在老的系統(tǒng)中部署。表 2 列出此文件中的重要屬性及其含義:

    表 2. MANIFEST.MF 文件屬性

    屬性名字含義
    Bundle-ActivatorBundle 的啟動(dòng)器
    Bundle-SymbolicName名稱(chēng),一般使用類(lèi)似于 JAVA 包路徑的名字命名
    Bundle-Version版本,注意不同版本的同名 bundle 可以同時(shí)上線部署
    Export-Package導(dǎo)出的 package 聲明,其它的 bundle 可以直接引用
    Import-Package導(dǎo)入的 package
    Eclipse-LazyStart是否只有當(dāng)被引用了才啟動(dòng)
    Require-Bundle全依賴(lài)的 bundle,不推薦
    Bundle-ClassPath本 bundle 的 class path,可以包含其它一些資源路徑
    Bundle-RequiredExecutionEnvironment本 bundle 必須的執(zhí)行環(huán)境,例如 jdk 版本聲明

    重要的理論知識(shí)

    好的,剛才我們已經(jīng)從頭到尾開(kāi)發(fā)了一個(gè)基于 Equinox 框架的 Hello world 應(yīng)用程序。我們發(fā)現(xiàn)似乎并不是很困難,很多工作 Eclipse 已經(jīng)幫我們做好了,例如 Activator 代碼框架和 MANIFEST.MF 文件,我們也學(xué)會(huì)了如何控制 OSGi 的控制臺(tái)和編寫(xiě) MANIFEST.MF 文件,但是,您真的明白它們是如何運(yùn)行的么?下面我們將重點(diǎn)介紹一些 OSGi 運(yùn)行必備的基礎(chǔ)知識(shí)。

    什么是 bundle?

    我們已經(jīng)看到,編寫(xiě)一個(gè)很普通的 Hello world 應(yīng)用,必須首先創(chuàng)建一個(gè) plug-in 工程,然后編輯其 Activator 類(lèi)的?start?方法,實(shí)際我們這樣做的本質(zhì)是為 OSGi 運(yùn)行環(huán)境添加了一個(gè) bundle,那么一個(gè) bundle 必須的構(gòu)成元素是哪些呢?

  • MANIFEST.MF:描述了 bundle 的所有特征,包括名字、輸出的類(lèi)或者包,導(dǎo)入的類(lèi)或者包,版本號(hào)等等,具體可以參考 表 2. MANIFEST.MF 文件屬性。
  • 代碼:包括 Activator 類(lèi)和其它一些接口以及實(shí)現(xiàn),這個(gè)和普通的 Java 應(yīng)用程序沒(méi)有什么特殊的區(qū)別。
  • 資源:當(dāng)然,一個(gè)應(yīng)用程序不可能沒(méi)有資源文件,比如圖片、properties 文件、XML 文件等等,這些資源可以隨 bundle 一起存在,也可以以 fragment bundle 的方式加入。
  • 啟動(dòng)級(jí)別的定義:可以在啟動(dòng)前使用命令行參數(shù)指定,也可以在運(yùn)行中指定,具體的 start level 的解釋,請(qǐng)參考 后面的說(shuō)明。
  • 框架做了些什么?

    好了,我們已經(jīng)明白 bundle 是什么了,也知道如何開(kāi)發(fā)一個(gè)基本的 bundle 了,那么我們還必須要明白,我的 bundle 放在 Equinox 框架中,它對(duì)我們的 bundle 做了些什么?

    圖 11. Equinox 框架架構(gòu)

    實(shí)際上,目標(biāo)平臺(tái)已經(jīng)為我們準(zhǔn)備了 N 個(gè) bundle,它們提供各種各樣的服務(wù),OSGi 中,這些 bundle 的名字叫 system bundle,就好比精裝修的房子,您只需要拎包入住,不再需要自己鋪地板,裝吊頂了。

    我們的 bundle 進(jìn)入 Equinox 環(huán)境后,OSGi 框架對(duì)其做的事情如下:

  • 讀入 bundle 的 headers 信息,即 MANIFEST.MF 文件;
  • 裝載相關(guān)的類(lèi)和資源;
  • 解析依賴(lài)的包;
  • 調(diào)用其 Activator 的?start?方法,啟動(dòng)它;
  • 為其提供框架事件、服務(wù)事件等服務(wù);
  • 調(diào)用其 Activator 的?stop?方法,停止它;
  • Bundle 的狀態(tài)變更

    OK, 現(xiàn)在我們大概明白了一個(gè) bundle 的定義和其在 OSGi 框架中的生命周期,前面我們看到控制臺(tái)可以通過(guò)?ss?命令查看所有裝載的 bundle 的狀態(tài),那么 bundle 到底具有哪些狀態(tài),這些狀態(tài)之間是如何變換呢?我們知道了這些狀態(tài)信息,對(duì)我們有何益處?

    首先,了解一下一個(gè) bundle 到底有哪些狀態(tài):

    表 3. Bundle 狀態(tài)表

    狀態(tài)名字含義
    INSTALLED就是字面意思,表示這個(gè) bundle 已經(jīng)被成功的安裝了
    ??
    RESOLVED很常見(jiàn)的一個(gè)狀態(tài),表示這個(gè) bundle 已經(jīng)成功的被解析(即所有依賴(lài)的類(lèi)、資源都找到了),通常出現(xiàn)在啟動(dòng)前或者停止后
    STARTING字面意思,正在啟動(dòng),但是還沒(méi)有返回,所以您的 Activator 不要搞的太復(fù)雜
    ACTIVE活動(dòng)的,這是我們最希望看到的狀態(tài),通常表示這個(gè) bundle 已經(jīng)啟動(dòng)成功,但是不意味著您的 bundle 提供的服務(wù)也是 OK 的
    STOPPING字面意思,正在停止,還沒(méi)有返回
    UNINSTALLED卸載了,狀態(tài)不能再發(fā)生變更了

    下面請(qǐng)看一張經(jīng)典的 OSGi bundle 變更狀態(tài)的圖:

    圖 12. OSGi bundle 變更狀態(tài)圖

    Bundle 導(dǎo)入導(dǎo)出 package

    OK,到現(xiàn)在為止,似乎一切都是新鮮的,但是您似乎在考慮,OSGi 到底有什么優(yōu)勢(shì),下面介紹一下其中的一個(gè)特點(diǎn),幾乎所有的面向組件的框架都需要這一點(diǎn)來(lái)實(shí)現(xiàn)其目的:面向服務(wù)、封裝實(shí)現(xiàn)。這一點(diǎn)在普通的 Java 應(yīng)用是很難做到的,所有的類(lèi)都暴露在 classpath 中,人們可以隨意的查看您的實(shí)現(xiàn),甚至變更您的實(shí)現(xiàn)。這一點(diǎn),對(duì)于希望發(fā)布組件的公司來(lái)說(shuō)是致命的。

    圖 13. OSGi bundle 原理

    OSGi 很好的解決了這個(gè)問(wèn)題,就像上面的圖顯示的,每個(gè) bundle 都可以有自己公共的部分和隱藏的部分,每個(gè) bundle 也只能看見(jiàn)自己的公共部分、隱藏部分和其它 bundle 的公共部分。

    bundle 的 MANIFEST.MF 文件提供了 EXPORT/IMPORT package 的關(guān)鍵字,這樣您可以?xún)H僅 export 出您希望別人看到的包,而隱藏實(shí)現(xiàn)的包。并且您可以為它們編上版本號(hào),這樣可以同時(shí)發(fā)布不同版本的包。

    Bundle class path

    這一點(diǎn)比較難理解,一般情況下您不需要關(guān)心這個(gè)事情,除非事情出現(xiàn)了問(wèn)題,您發(fā)現(xiàn)明明這個(gè)類(lèi)就在這里,怎么就是報(bào)告 ClassNotFoundException/NoClassDefExcpetion 呢?在您垂頭喪氣、準(zhǔn)備砸掉電腦顯示器之前,請(qǐng)看一下 bundle 中的類(lèi)是如何查找的:

  • 首先,它會(huì)找 JRE,這個(gè)很明顯,這個(gè)實(shí)際是通過(guò)系統(tǒng)環(huán)境的?JAVA_HOME?中找到的,路徑一般是 JAVA_HOME/lib/rt.jar、tools.jar 和 ext 目錄,endorsed 目錄。
  • 其次,它會(huì)找 system bundle 導(dǎo)出的包。
  • 然后,它會(huì)找您的 import 的包,這個(gè)實(shí)際包含兩種:一種是直接通過(guò) require-bundle 的方式全部導(dǎo)入的,還有一種就是前面講的通過(guò) import package 方式導(dǎo)入的包。
  • 查找它的 fragment bundle,如果有的話。
  • 如果還沒(méi)有找到,則會(huì)找自己的 classpath 路徑(每個(gè) bundle 都有自己的類(lèi)路徑)。
  • 最后它會(huì)嘗試根據(jù) DynamicImport-Package 屬性查找的引用。
  • 啟動(dòng)級(jí)別 Start level

    在 Equinox 環(huán)境中,我們?cè)谂渲?hello world 應(yīng)用的時(shí)候,看到我們將 framework start level 保持為 4,將 Hello world bundle 的 start level 設(shè)置為 5 。 start level 越大,表示啟動(dòng)的順序越靠后。在實(shí)際的應(yīng)用環(huán)境中,我們的 bundle 互相有一定的依賴(lài)關(guān)系,所以在啟動(dòng)的順序上要有所區(qū)別,好比蓋樓,要從打地基開(kāi)始。

    實(shí)際上,OSGi 框架最初的 start level 是 0,啟動(dòng)順序如下:

  • 將啟動(dòng)級(jí)別加一,如果發(fā)現(xiàn)有匹配的 bundle(即 bundle 的啟動(dòng)級(jí)別和目前的啟動(dòng)級(jí)別相等),則啟動(dòng)這個(gè) bundle;
  • 繼續(xù)第一步,直到發(fā)現(xiàn)已經(jīng)啟動(dòng)了所有的 bundle,且活動(dòng)啟動(dòng)級(jí)別和最后的啟動(dòng)的 bundle 啟動(dòng)級(jí)別相同。
  • 停止順序,也是首先將系統(tǒng)的 start level 設(shè)置為 0:

  • 由于系統(tǒng)當(dāng)前活動(dòng)啟動(dòng)級(jí)別大于請(qǐng)求的 start level,所以系統(tǒng)首先停止等于當(dāng)前活動(dòng)啟動(dòng)級(jí)別的 bundle;
  • 將活動(dòng)啟動(dòng)級(jí)別減一,繼續(xù)第一步,直到發(fā)現(xiàn)活動(dòng)啟動(dòng)級(jí)別和請(qǐng)求級(jí)別相等,都是 0。
  • 開(kāi)發(fā)一個(gè)真實(shí)的 OSGi 應(yīng)用程序

    我們不能只停留在 hello world 的層面,雖然那曾經(jīng)對(duì)我們很重要 ,但是現(xiàn)實(shí)需要我們能夠使用 OSGi 寫(xiě)出激動(dòng)人心的應(yīng)用程序,它能夠被客戶(hù)接受,被架構(gòu)師認(rèn)可,被程序員肯定。好的,那我們開(kāi)始吧。下面將會(huì)著重介紹一些現(xiàn)實(shí)的應(yīng)用程序可能需要的一些 OSGi 應(yīng)用場(chǎng)景。

    發(fā)布和使用服務(wù)

    由于 OSGi 框架能夠方便的隱藏實(shí)現(xiàn)類(lèi),所以對(duì)外提供接口是很自然的事情,OSGi 框架提供了服務(wù)的注冊(cè)和查詢(xún)功能。好的,那么我們實(shí)際操作一下,就在 Hello world 工程的基礎(chǔ)上進(jìn)行。

    我們需要進(jìn)行下列的步驟:

  • 定義一個(gè)服務(wù)接口,并且 export 出去供其它 bundle 使用;
  • 定義一個(gè)缺省的服務(wù)實(shí)現(xiàn),并且隱藏它的實(shí)現(xiàn);
  • Bundle 啟動(dòng)后,需要將服務(wù)注冊(cè)到 Equinox 框架;
  • 從框架查詢(xún)這個(gè)服務(wù),并且測(cè)試可用性。
  • 好的,為了達(dá)到上述要求,我們實(shí)際操作如下:

  • 定義一個(gè)新的包?osgi.test.helloworld.service?,用來(lái)存放接口。單獨(dú)一個(gè) package 的好處是,您可以?xún)H僅 export 這個(gè) package 給其它 bundle 而隱藏所有的實(shí)現(xiàn)類(lèi)
  • 在上述的包中新建接口?IHello,提供一個(gè)簡(jiǎn)單的字符串服務(wù),代碼如下:

    清單 2. IHello

    1

    2

    3

    4

    5

    6

    7

    8

    9

    package osgi.test.helloworld.service;

    ?

    public interface IHello {

    ????/**

    ?????* 得到 hello 信息的接口 .

    ?????* @return the hello string.

    ?????*/

    ????String getHello();

    }

  • 再新建一個(gè)新的包?osgi.test.helloworld.impl,用來(lái)存放實(shí)現(xiàn)類(lèi)。
  • 在上述包中新建?DefaultHelloServiceImpl?類(lèi),實(shí)現(xiàn)上述接口:

    清單 3. IHello 接口實(shí)現(xiàn)

    1

    2

    3

    4

    5

    6

    7

    8

    public class DefaultHelloServiceImpl implements IHello {

    ?

    ????@Override

    ????public String getHello() {

    ????????return "Hello osgi,service";

    ????}

    ?

    ?}

  • 注冊(cè)服務(wù),OSGi 框架提供了兩種注冊(cè)方式,都是通過(guò)?BundleContext?類(lèi)實(shí)現(xiàn)的:
  • registerService(String,Object,Dictionary)?注冊(cè)服務(wù)對(duì)象?object?到接口名?String?下,可以攜帶一個(gè)屬性字典?Dictionary;
  • registerService(String[],Object,Dictionary)?注冊(cè)服務(wù)對(duì)象?object?到接口名數(shù)組?String[]?下,可以攜帶一個(gè)屬性字典?Dictionary,即一個(gè)服務(wù)對(duì)象可以按照多個(gè)接口名字注冊(cè),因?yàn)轭?lèi)可以實(shí)現(xiàn)多個(gè)接口;
  • 我們使用第一種注冊(cè)方式,修改?Activator?類(lèi)的?start?方法,加入注冊(cè)代碼:

    清單 4. 加入注冊(cè)代碼

    1

    2

    3

    4

    5

    6

    7

    8

    9

    public void start(BundleContext context) throws Exception {

    ?????????

    ????System.out.println("hello world");

    ????context.registerService(

    ????????IHello.class.getName(),

    ????????new DefaultHelloServiceImpl(),

    ????????null);

    ?????????

    }

  • 為了讓我們的服務(wù)能夠被其它 bundle 使用,必須在 MANIFEST.MF 中對(duì)其進(jìn)行導(dǎo)出聲明,雙擊 MANIFEST.MF,找到?runtime > exported packages > 點(diǎn)擊 add,如圖,選擇?service?包即可:

    圖 14. 選擇導(dǎo)出的服務(wù)包

  • 另外新建一個(gè)類(lèi)似于 hello world 的 bundle 叫:osgi.test.helloworld2,用于測(cè)試osgi.test.helloworld?bundle 提供的服務(wù)的可用性;
  • 添加 import package:在第二個(gè) bundle 的 MANIFEST.MF 文件中,找到?dependencies > Imported packages > Add …,選擇我們剛才 export 出去的?osgi.test.helloworld.service?包:

    圖 15. 選擇剛才 export 出去的 osgi.test.helloworld.service 包

  • 查詢(xún)服務(wù):同樣,OSGi 框架提供了兩種查詢(xún)服務(wù)的引用?ServiceReference?的方法:
  • getServiceReference(String):根據(jù)接口的名字得到服務(wù)的引用;
  • getServiceReferences(String,String):根據(jù)接口名和另外一個(gè)過(guò)濾器名字對(duì)應(yīng)的過(guò)濾器得到服務(wù)的引用;
  • 這里我們使用第一種查詢(xún)的方法,在?osgi.test.helloworld2?bundle 的?Activator?的?start?方法加入查詢(xún)和測(cè)試語(yǔ)句:

    清單 5. 加入查詢(xún)和測(cè)試語(yǔ)句

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    public void start(BundleContext context) throws Exception {

    ????System.out.println("hello world2");

    ?????????

    ????/**

    ????????* Test hello service from bundle1.

    ????*/

    ????IHello hello1 =

    ????????(IHello) context.getService(

    ????????context.getServiceReference(IHello.class.getName()));

    ????????System.out.println(hello1.getHello());

    }

  • 修改運(yùn)行環(huán)境,因?yàn)槲覀冊(cè)黾恿艘粋€(gè) bundle,所以說(shuō)也需要在運(yùn)行配置中加入對(duì)新的 bundle 的配置信息,如下圖所示:

    圖 16. 加入對(duì)新的 bundle 的配置信息

  • 執(zhí)行,得到下列結(jié)果:

    圖 17. 執(zhí)行結(jié)果

  • 恭喜您,成功了!

    使用事件管理服務(wù) EventAdmin

    前面講過(guò),OSGi 規(guī)范定義了很多可用的 bundle,您盡管使用它們完成您的工作,而不必另外再發(fā)明輪子,OSGi 框架定義的事件管理服務(wù),類(lèi)似于 JMS,但是使用上比 JMS 簡(jiǎn)單。

    OSGi 整個(gè)框架都離不開(kāi)這個(gè)服務(wù) ,因?yàn)榭蚣芾锩嫒家揽渴录C(jī)制進(jìn)行通信,例如 bundle 的啟動(dòng)、停止,框架的啟動(dòng)、停止,服務(wù)的注冊(cè)、注銷(xiāo)等等等等都是會(huì)發(fā)布事件給監(jiān)聽(tīng)者,同時(shí)也在監(jiān)聽(tīng)其它模塊發(fā)來(lái)的自己關(guān)心的事件。 OSGi 框架的事件機(jī)制主要核心思想是:

  • 用戶(hù)(程序員)可以自己按照接口定義自己的事件類(lèi)型
  • 用戶(hù)可以監(jiān)聽(tīng)自己關(guān)心的事件或者所有事件
  • 用戶(hù)可以將事件同步的或者異步的提交給框架,由框架負(fù)責(zé)同步的或者異步的分發(fā)給監(jiān)聽(tīng)者
  • 說(shuō)明:框架提供的事件服務(wù)、事件提供者、事件監(jiān)聽(tīng)者之間的關(guān)系如下:

    圖 18. 事件服務(wù)、事件提供者、事件監(jiān)聽(tīng)者之間的關(guān)系

    事件提供者 Publisher 可以獲取 EventAdmin 服務(wù),通過(guò) sendEvent 同步(postEvent 異步)方式提交事件,EventAdmin 服務(wù)負(fù)責(zé)分發(fā)給相關(guān)的監(jiān)聽(tīng)者 EventHandler,調(diào)用它們的?handleEvent?方法。

    這里要介紹一個(gè)新的概念 Topics,其實(shí)在 JMS 里面也有用,也就是說(shuō)一個(gè)事件一般都有一個(gè)主題,這樣我們的事件接收者才能按照一定的主題進(jìn)行過(guò)濾處理,例如只處理自己關(guān)心的主題的事件,一般情況下主題是用類(lèi)似于 Java Package 的命名方式命名的。

    同步提交(sendEvent)和異步提交(postEvent) 事件的區(qū)別是,同步事件提交后,等框架分發(fā)事件給所有事件接收者之后才返回給事件提交者,而異步事件則一經(jīng)提交就返回了,分發(fā)在另外的線程進(jìn)行處理。

    下面的程序演示了事件的定義、事件的發(fā)布、事件處理,同時(shí)還演示了同步和異步處理的效果,以及運(yùn)行環(huán)境的配置。

    (約定?osgi.test.helloworld?為 bundle1,osgi.test.helloworld2?為 bundle2)

    圖 19. 同步和異步處理演示

  • 在 bundle1 中的 MANIFEST.MF 的 dependency 頁(yè)面中定義引入新的包:org.osgi.service.event。
  • 在 bundle1 中的?osgi.test.helloworld.event?包中定義新的類(lèi)?MyEvent,如下(注意其中的 topic 定義的命名方式):

    清單 6. 定義新的類(lèi) MyEvent

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    import java.util.Dictionary;

    import org.osgi.service.event.Event;

    ?

    public class MyEvent extends Event {

    ????public static final String MY_TOPIC = "osgi/test/helloworld/MyEvent";

    ????public MyEvent(String arg0, Dictionary arg1) {

    ????????super(MY_TOPIC, arg1);

    ????}

    ????public MyEvent() {

    ????????super(MY_TOPIC, null);

    ????}

    ?

    ????public String toString() {

    ????????return "MyEvent";

    ????}

    ?}

  • 在 bundle1 的?DefaultHelloServiceHandler?類(lèi)的?getHello?方法中,加入提交事件的部分,這樣 bundle2 在調(diào)用這個(gè)服務(wù)的時(shí)候,將觸發(fā)一個(gè)事件,由于采用了 Post 方式,應(yīng)該是立刻返回的,所以在?postEvent?前后打印了語(yǔ)句進(jìn)行驗(yàn)證。

    清單 7. getHello 方法

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    import org.osgi.framework.BundleContext;

    import org.osgi.framework.ServiceReference;

    import org.osgi.service.event.EventAdmin;

    ?

    @Override

    public String getHello() {

    ?????????

    ????//post a event

    ????ServiceReference ref =

    ????????context.getServiceReference(EventAdmin.class.getName());

    ????if(ref!=null) {

    ????????eventAdmin = (EventAdmin)context.getService(ref);

    ????????if(eventAdmin!=null) {

    ????????????System.out.println("post event started");

    ????????????eventAdmin.postEvent(new MyEvent());

    ????????????System.out.println("post event returned");

    ????????}

    ????}

    ?????????

    ????return "Hello osgi,service";

    }

  • 定義監(jiān)聽(tīng)者,在 bundle2 中,也引入 osgi 的事件包,然后定義一個(gè)新的類(lèi):MyEventHandler?類(lèi),用來(lái)處理事件,這里故意加入了一個(gè)延遲,是為了測(cè)試異步事件的調(diào)用,實(shí)現(xiàn)如下:

    清單 8. MyEventHandler 類(lèi)

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    import org.osgi.service.event.Event;

    import org.osgi.service.event.EventHandler;

    ?

    public class MyEventHandler implements EventHandler {

    ?

    ????@Override

    ????public void handleEvent(Event event) {

    ????????System.out.println("handle event started--"+event);

    ????????try {

    ????????????Thread.currentThread().sleep(5*1000);

    ????????} catch (InterruptedException e) {

    ?????????????

    ????????}

    ????????System.out.println("handle event ok--"+event);

    ?????}

    ?}

  • 注冊(cè)監(jiān)聽(tīng)器,有了事件處理器,還需要注冊(cè)到監(jiān)聽(tīng)器中,這里在 bundle2 的?Activator?類(lèi)中加入此監(jiān)聽(tīng)器,也就是調(diào)用?context.registerService?方法注冊(cè)這個(gè)監(jiān)聽(tīng)服務(wù),和普通服務(wù)的區(qū)別是要帶一個(gè)監(jiān)聽(tīng)事件類(lèi)型的 topic,這里列出?Activator?類(lèi)的?start?方法:

    清單 9. start 方法

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    import java.rmi.registry.LocateRegistry;

    import java.rmi.registry.Registry;

    import java.util.Hashtable;

    ?

    import org.osgi.framework.BundleActivator;

    import org.osgi.framework.BundleContext;

    import org.osgi.service.event.EventConstants;

    import org.osgi.service.event.EventHandler;

    ?

    import osgi.test.helloworld.event.MyEvent;

    import osgi.test.helloworld.service.IAppService;

    import osgi.test.helloworld.service.IHello;

    ?

    public void start(BundleContext context) throws Exception {

    ?????

    ????System.out.println("hello world2");

    ?????????

    ????/**

    ????* 添加事件處理器 .

    ????*/

    ????String[] topics = new String[] {MyEvent.MY_TOPIC};

    ????Hashtable<String,String[]> ht = new Hashtable<String,String[]>();

    ????ht.put(EventConstants.EVENT_TOPIC, topics);

    ????EventHandler myHandler = new MyEventHandler();

    ????context.registerService(

    ????????EventHandler.class.getName(),

    ????????myHandler,

    ????????ht);

    ????System.out.println("event handler registered");

    ?????????

    ????/**

    ????* Test hello service from bundle1.

    ????*/

    ????IHello hello1 =

    ????????(IHello) context.getService(

    ????????context.getServiceReference(IHello.class.getName()));

    ????System.out.println(hello1.getHello());

    }

  • 為了使用框架的事件服務(wù),需要修改運(yùn)行環(huán)境,加入兩個(gè)系統(tǒng) bundle,分別是:
  • org.eclipse.osgi.services
  • org.eclipse.equinox.event
  • 好了一切準(zhǔn)備好了,執(zhí)行:

    圖 20. 執(zhí)行

    可以看到,post?事件后,不等事件真的被處理完成,就返回了,事件處理在另外的線程執(zhí)行,最后才打印處理完成的語(yǔ)句。然后?ss?看一下,目前我們已經(jīng)有五個(gè) bundle 在運(yùn)行了:

    圖 21. ss 查詢(xún)

  • OK,修改代碼以測(cè)試同步調(diào)用的情況,我們只需要把提交事件的代碼由?postEvent?修改為sendEvent?即可。其它不變,測(cè)試結(jié)果如下:

    圖 22. 同步調(diào)用測(cè)試結(jié)果

  • 使用 Http 服務(wù) HttpService

    OSGi 的 HTTP 服務(wù)為我們提供了展示 OSGi 的另外一個(gè)途徑,即我們可以專(zhuān)門(mén)提供一個(gè) bundle 用來(lái)作為我們應(yīng)用的 UI,當(dāng)然這個(gè)還比較簡(jiǎn)單,只能提供基本的 HTML 服務(wù)和基本的 Servlet 服務(wù)。如果想提供復(fù)雜的 Jsp/Struts/WebWorks 等等,或者想用現(xiàn)有的 Web 中間件服務(wù)器例如 Tomcat/Resin/WebSphere Application Server 等,都需要另外的途徑來(lái)實(shí)現(xiàn),目前我提供一些基本的使用 HTTP 服務(wù)的方式。

    要使用 HTTP 服務(wù),必然有三個(gè)步驟

  • 獲取 HttpService,可以像 上述方式 那樣通過(guò) context 的?getService?方法獲得引用;
  • 使用 HttpService 的引用注冊(cè)資源或者注冊(cè) Servlet:
  • registerResources:注冊(cè)資源,提供本地路徑、虛擬訪問(wèn)路徑和相關(guān)屬性即可完成注冊(cè),客戶(hù)可以通過(guò)虛擬訪問(wèn)路徑 + 資源名稱(chēng)訪問(wèn)到資源
  • registerServlet:注冊(cè) Servlet,提供標(biāo)準(zhǔn) Servlet 實(shí)例、虛擬訪問(wèn)路徑、相關(guān)屬性以及 HttpContext(可以為 null)后即可完成注冊(cè),客戶(hù)可以直接通過(guò)虛擬訪問(wèn)路徑獲取該 Servlet 的訪問(wèn)
  • 修改運(yùn)行環(huán)境,加入支持 http 服務(wù)的 bundle
  • 那么,接下來(lái)我們實(shí)際操作一下:

  • 首先,在 bundle1 的 src 中建立一個(gè)新的 package,名字叫 pages,用來(lái)存放一些 HTML 的資源文件,為了提供一個(gè)基本的 HTTP 服務(wù),我們需要提供一個(gè) index.html,內(nèi)容如下:

    1

    2

    3

    <html>

    ????<h1>hello osgi http service</h1>

    </html>

  • 第二步,注冊(cè)資源服務(wù),首先我們要為 bundle1 加入 HTTP 服務(wù)的 package 引用,即修改 MANIFEST.MF 文件的 dependencies,加入包:org.osgi.service.http;version="1.2.0",然后在?Activator?類(lèi)的?start?方法中加入 HTTP 資源的注冊(cè):

    清單 10. 加入 HTTP 資源的注冊(cè)代碼

    1

    2

    3

    httpService = (HttpService)context.getService

    ????(context.getServiceReference(HttpService.class.getName()));

    httpService.registerResources("/", "/pages", null);

  • 修改運(yùn)行環(huán)境,在?target platform?的 bundle 列表中加入:org.eclipse.equinox.http?和javax.servlet?這兩個(gè) bundle 保證了 HttpService 的可用性:

    圖 23. 加入 HttpService bundle

  • 運(yùn)行,然后打開(kāi) IE 訪問(wèn)本機(jī)?http://localhost/index.html:

    圖 24. 運(yùn)行結(jié)果

  • 加入 servlet,首先在 bundle1 建立一個(gè)包:osgi.test.hellworld.servlet,建立一個(gè)新的類(lèi):MyServlet,要從?HttpServlet?基類(lèi)繼承,實(shí)現(xiàn)其?doGet?方法,如下:

    清單 11. MyServlet 代碼

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    import java.io.IOException;

    import java.util.Date;

    ?

    import javax.servlet.http.HttpServlet;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    ?

    public class MyServlet extends HttpServlet {

    ????/**

    ?????* 實(shí)現(xiàn)測(cè)試 .

    ?????* @param request the req.

    ?????* @param response the res.

    ?????* @throws IOException io exception.

    ?????*/

    ????public void doGet(

    ????????????HttpServletRequest request,

    ????????????HttpServletResponse response

    ????????????) throws IOException {

    ????????response.getWriter()

    ????????????.write("hello osgi http servlet.time now is "+new Date());

    ????}

    ?}

  • 注冊(cè) servlet,在?Activator?類(lèi)的?start?方法中加入注冊(cè) servlet 的代碼,如下:

    清單 12. 注冊(cè) servlet 的代碼

    1

    2

    MyServlet ms = new MyServlet();

    httpService.registerServlet("/ms", ms, null, null);

  • 運(yùn)行,打開(kāi) IE 訪問(wèn)?http://localhost/ms?后得到結(jié)果:

    圖 25. 運(yùn)行結(jié)果

  • 分布式部署的實(shí)現(xiàn)

    分布式部署的實(shí)現(xiàn)方式一般可以通過(guò) Web 服務(wù)、RMI 等方式,這里簡(jiǎn)單介紹一下基于 RMI 方式的分布式實(shí)現(xiàn)。

    在 OSGi 環(huán)境中,并沒(méi)有直接提供分布式部署的支持,我們可以采用 J2SE 提供的 RMI 方式來(lái)實(shí)現(xiàn),但是要考慮 OSGi 的因素,即如果您希望您的服務(wù)既可以本地使用,也可以被遠(yuǎn)程訪問(wèn),那么您應(yīng)該這樣定義接口和類(lèi):

    圖 26. 以被遠(yuǎn)程訪問(wèn)需要定義的接口和類(lèi)

    說(shuō)明:

  • Remote?接口是 J2SE 定義的遠(yuǎn)程對(duì)象必須實(shí)現(xiàn)的接口;
  • IAppService?接口是 OSGi 服務(wù)接口,繼承了?Remote?接口,即定義方式為:

    1

    public interface IAppService extends Remote

  • AppServiceImpl?實(shí)現(xiàn)了?IAppService?接口,此外注意里面的方法都拋出?RemoteException?異常;
  • 實(shí)際操作如下:

  • 在 bundle1 的?service?包中加入?IAppService?接口的定義,繼承自?Remote?接口,定義個(gè)方法:

    清單 13. IAppService 接口定義

    1

    2

    3

    4

    5

    6

    7

    8

    public interface IAppService extends Remote {

    ????/**

    ?????* 得到一個(gè)遠(yuǎn)程服務(wù)的名稱(chēng) .

    ?????* @return .

    ?????* @throws RemoteException .

    ?????*/

    ????String getAppName() throws RemoteException;

    ?}

  • 把這個(gè)接口注冊(cè)為 OSGi 標(biāo)準(zhǔn)服務(wù)以及一個(gè) RMI 服務(wù)對(duì)象如下:

    注冊(cè)為標(biāo)準(zhǔn)服務(wù):

    清單 14. 注冊(cè)為標(biāo)準(zhǔn)服務(wù)

    1

    2

    3

    4

    5

    IAppService appService = new DefaultAppServiceImpl(context);

    context.registerService(

    ????IAppService.class.getName(),

    ????appService,

    ????null);

    注冊(cè)為遠(yuǎn)程對(duì)象:

    清單 15. 注冊(cè)為遠(yuǎn)程對(duì)象

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    /**

    * 啟動(dòng) rmi server .

    * @param service the service.

    * @throws RemoteException re.

    */

    private void startRmiServer(IAppService service) throws RemoteException {

    ????if(registry == null) {

    ????????registry = LocateRegistry.createRegistry(1099);

    ????}

    ????// 注冊(cè) appService 遠(yuǎn)程服務(wù) .

    ????IAppService theService =

    ????????(IAppService)UnicastRemoteObject.exportObject(service,0);

    ????registry.rebind("appService", theService);

    }

  • 在 bundle2 中通過(guò) OSGi 方式使用這個(gè)服務(wù):

    清單 16. 使用服務(wù)

    1

    2

    3

    4

    IAppService appService =

    ????(IAppService)context.getService(

    ????????context.getServiceReference(IAppService.class.getName()));

    System.out.println(appService.getAppName());

  • 通過(guò) RMI 方式使用這個(gè)服務(wù):

    清單 17. 通過(guò) RMI 方式使用服務(wù)

    1

    2

    3

    4

    5

    6

    7

    8

    9

    String host = "127.0.0.1";

    int port = 1099;

    try {

    ????Registry registry = LocateRegistry.getRegistry(host,port);

    ????appServiceStub = (IAppService) registry.lookup("appService");

    } catch (Exception e) {

    ????e.printStackTrace();

    }

    System.out.println("rmi:"+appServiceStub.getAppName());

  • 最終的運(yùn)行結(jié)果如下:

    圖 27. 運(yùn)行結(jié)果

  • 探討 OSGi 應(yīng)用架構(gòu)

    設(shè)計(jì)思路

    到目前為止,我們已經(jīng)涉及到了 OSGi 的諸多方面,那么在實(shí)際進(jìn)行應(yīng)用程序的架構(gòu)設(shè)計(jì)的時(shí)候我們要考慮哪些因素呢,這一節(jié)我們?cè)敿?xì)討論一下這個(gè)問(wèn)題。

    應(yīng)用架構(gòu)的設(shè)計(jì)應(yīng)該充分考慮到可靠性、可擴(kuò)展性、可維護(hù)性等因素,使用了 OSGi 框架后,我們可以更加容易的實(shí)現(xiàn)系統(tǒng)分層,組件化的設(shè)計(jì)方式。通過(guò)使用 HTTP 服務(wù)我們可以設(shè)計(jì)出一個(gè)基于 HTTP 服務(wù)的程序維護(hù)平臺(tái)。架構(gòu)如下:

    圖 28. 基于 HTTP 服務(wù)的程序維護(hù)平臺(tái)

    說(shuō)明:

  • 通用第三方庫(kù)層:這一層包括了常用的第三方庫(kù),例如 apache commons,jfreechart,xml 包等等,這一層需要將這些包全部 export 出去,這樣上層就可以直接通過(guò) require bundle 的方式使用這些包。
  • 業(yè)務(wù)模型定義層:這一層依賴(lài)于(require-bundle)通用第三方庫(kù)層,定義了應(yīng)用的業(yè)務(wù)模型,例如各種 JavaBeans,也可以在這一層提供額外的應(yīng)用統(tǒng)一配置服務(wù),即為上層應(yīng)用提供配置文件的管理服務(wù)。
  • 業(yè)務(wù)邏輯實(shí)現(xiàn)層:這一層依賴(lài)于(require-bundle)通用第三方庫(kù)層,還依賴(lài)于 (import package) 業(yè)務(wù)模型定義層提供的業(yè)務(wù)模型,定義了應(yīng)用的業(yè)務(wù)邏輯,這一層可以細(xì)分為:
  • DAO(Database Access Object)服務(wù)層:即為上層應(yīng)用提供數(shù)據(jù)庫(kù)存取服務(wù)的層,其 export 出去的接口全部都是和數(shù)據(jù)庫(kù)操作相關(guān)的;
  • Service 層:為 UI 層提供的業(yè)務(wù)邏輯的封裝層,這樣 UI 層只需要執(zhí)行 service 層的接口即可,可以將更多的精力放在 UI 的設(shè)計(jì);
  • 展現(xiàn)維護(hù)層:這一層依賴(lài)于(require-bundle)通用第三方庫(kù)層,和下面各層提供的管理服務(wù)接口,基于 HTTP 服務(wù)的方式提供應(yīng)用的維護(hù),例如配置文件的在線修改、服務(wù)的管理,bundle 的管理,日志的管理,內(nèi)存的管理等等,這些都可以以“ RUNTIME ”的方式展現(xiàn),管理員或者維護(hù)人員操作的就是 Equinox 運(yùn)行環(huán)境。還可以實(shí)現(xiàn)大部分的操作不需要重啟 JVM,這一點(diǎn)類(lèi)似于 JMX。
  • 事件服務(wù):事件服務(wù)層是 OSGi 框架提供的標(biāo)準(zhǔn)服務(wù)之一,為除了通用第三方庫(kù)層以外的各層提供事件服務(wù),包括同步、異步的通知各種事件、發(fā)布各種事件等。通過(guò)事件服務(wù),可以實(shí)現(xiàn)各層之間的聯(lián)動(dòng)。
  • 這種架構(gòu)的優(yōu)勢(shì)在于:

  • 各層只用關(guān)心自己的業(yè)務(wù),例如通用第三方庫(kù)層只需要 export,其它事情不用管,它也沒(méi)有自己的 Activator 類(lèi),業(yè)務(wù)模型定義層只需要關(guān)心業(yè)務(wù)模型,而不必關(guān)心業(yè)務(wù)的流程,業(yè)務(wù)邏輯層中的 DAO 層則只需要關(guān)心數(shù)據(jù)庫(kù)操作,service 層則負(fù)責(zé)組合業(yè)務(wù)流程。各司其職,這樣才能精于自己的模塊;
  • 較好的可維護(hù)性:最上層的維護(hù)展現(xiàn)層,為管理員提供了一個(gè) OSGi 應(yīng)用的管理窗口,提供在線重啟服務(wù)、管理各個(gè) bundle 和服務(wù)的能力,提供了類(lèi)似于 JMX 的能力;
  • 統(tǒng)一的事件管理框架:為各層定義了統(tǒng)一的事件管理接口,基于 TOPIC 方式的事件監(jiān)聽(tīng)機(jī)制能夠有效的過(guò)濾事件,而且提供了異步、同步兩種方式對(duì)事件進(jìn)行處理,可以說(shuō)有相當(dāng)大的靈活性。
  • 可維護(hù)性的考慮

    一般的應(yīng)用架構(gòu)可能都比較多的考慮可靠性、靈活性、可擴(kuò)展性等,對(duì)可維護(hù)性卻沒(méi)有提供太多的關(guān)注,使用 OSGi 后,將對(duì)可維護(hù)性提供類(lèi)似于 JMX 的支持,當(dāng)然這不需要您實(shí)現(xiàn) MBEAN,就像上述介紹的架構(gòu)設(shè)計(jì),我們?cè)谧钌蠈涌梢栽O(shè)計(jì)一個(gè)基于 HTTP 的維護(hù)層,這樣,提供了一個(gè)小的 Web 控制臺(tái),供管理員進(jìn)行維護(hù)。

    維護(hù)的方面包括:

  • 系統(tǒng)維護(hù)
  • Bundle 的管理:包括每個(gè) bundle 的更新、停止、啟動(dòng);
  • 服務(wù)的管理:包括運(yùn)行環(huán)境注冊(cè)的服務(wù)的列表、停止、啟動(dòng);
  • 系統(tǒng)所有服務(wù)的重啟、停止、啟動(dòng);
  • 系統(tǒng)狀態(tài)的監(jiān)控
  • 對(duì)各個(gè)業(yè)務(wù)層提供的服務(wù)的狀態(tài)進(jìn)行實(shí)時(shí)監(jiān)視、統(tǒng)計(jì);
  • 對(duì)各個(gè)業(yè)務(wù)層提供服務(wù)的狀態(tài)進(jìn)行控制,通過(guò) OSGi 事件的方式進(jìn)行通知;
  • 系統(tǒng)日志的管理
  • 對(duì)系統(tǒng)中各個(gè)層的日志進(jìn)行統(tǒng)一列表、查看;
  • 對(duì)系統(tǒng)中所有操作進(jìn)行統(tǒng)一日志記錄、管理;
  • 配置管理
  • 對(duì)各個(gè)業(yè)務(wù)模塊需要的配置文件進(jìn)行統(tǒng)一展示;
  • 對(duì)各個(gè)業(yè)務(wù)模塊提供的配置文件提供在線編輯、提交功能;
  • 對(duì)修改后的配置文件提供實(shí)時(shí)上線的功能;
  • 其它
  • 維護(hù)系統(tǒng)的登錄、登出;
  • 維護(hù)系統(tǒng)自審計(jì);
  • 維護(hù)系統(tǒng)權(quán)限控制;
  • 部署 OSGi 應(yīng)用程序

    我們的 bundle 不會(huì)只能在 Eclipse 環(huán)境運(yùn)行,我們需要能夠?qū)?bundle 部署到實(shí)際的操作系統(tǒng)中,可能是 Windows/Linux/Unix 等環(huán)境,這要求我們按照下列步驟進(jìn)行:

  • 發(fā)布 bundle,即將我們的 plug-in 工程發(fā)布為可以執(zhí)行的 Jar 文件或者其它格式;
  • 配置 config.ini,指出 bundle 的運(yùn)行環(huán)境,啟動(dòng)順序等;
  • 啟動(dòng)腳本編寫(xiě),編寫(xiě)能夠運(yùn)行在各種操作系統(tǒng)的腳本;
  • 發(fā)布 Bundle

    發(fā)布 bundle 的工作其實(shí)很簡(jiǎn)單,通過(guò) eclipse 平臺(tái)即可完成:

  • 選擇 Eclipse 的?plug-in?視圖的?File -> Export,從彈出的窗口中選擇?Deployable plug-ins and fragments

    圖 29. 選擇 Deployable plug-ins and fragments

  • 在下一個(gè)窗口中,選擇想要發(fā)布的 bundle,這里我們選擇?osgi.test.helloworldosgi.test.helloworld2?工程,下面的 options 里面選擇“打包為一個(gè) Jar ”,目標(biāo)目錄選擇為?osgi.test.deploy?目錄(在當(dāng)前的 workspace 下面);
  • 選擇確定,發(fā)布后的目錄結(jié)構(gòu)如下圖所示,eclipse 幫我們?cè)诓渴鸶夸浵陆⒘艘粋€(gè)新的子目錄 plugins(類(lèi)似于 eclipse,因?yàn)?eclipse 就是基于 OSGi 的):

    圖 30. 發(fā)布后的目錄結(jié)構(gòu)

  • 好了,到這里,發(fā)布工作完成。
  • Config.ini

    為了讓我們的 Jar 文件跑起來(lái),需要 OSGi 的運(yùn)行環(huán)境支持,所以我們需要拷貝一些 system bundle 到 plugins 目錄中,包括:

    圖 31. OSGi 的運(yùn)行環(huán)境支持

    然后,把 eclipse 目錄的 org.eclipse.osgi_3.3.2.R33x_v20080105 文件拷貝到 osgi.test.deploy 根目錄,重命名為 equinox.jar 文件。

    在 osgi.test.deploy 目錄新建子目錄 configuration,新建一個(gè)文本文件 config.ini,用來(lái)配置 bundle 的啟動(dòng)環(huán)境,配置如下:

    圖 32. config.ini 配置文件

    注意最后兩個(gè) bundle 的啟動(dòng)順序配置格式為:bundle@start_leve:start。

    好了,config.ini 也已經(jīng)準(zhǔn)備好了。

    啟動(dòng)腳本

    下面進(jìn)行啟動(dòng)腳本編寫(xiě),這個(gè)和普通的 Java 程序沒(méi)有什么大的區(qū)別,都是調(diào)用 Java 程序執(zhí)行一個(gè) jar 文件,關(guān)鍵是其中的一些參數(shù)定義:

    圖 33. 啟動(dòng)腳本

    注意?1/2/3/117/118?參數(shù)都是 OSGi 環(huán)境特有的。

    運(yùn)行

    雙擊 run.bat,可以看到如下結(jié)果:

    圖 34. 運(yùn)行結(jié)果

    總結(jié)

    通過(guò)閱讀本文您應(yīng)該已經(jīng)掌握了使用 Equinox 開(kāi)發(fā)基于 OSGi 的應(yīng)用程序的方法,了解了其關(guān)鍵的理論知識(shí),還學(xué)習(xí)了如何開(kāi)發(fā)分層的, 模塊化的、分布式的應(yīng)用程序,掌握了在 Windows 平臺(tái)部署基于 Equinox 平臺(tái)的 OSGi 應(yīng)用程序的方法。總體上看,OSGi 能夠有效的降低模塊 之間的耦合程度,將軟件設(shè)計(jì)的開(kāi)閉原則(Open-Close Principle)提高到一個(gè)新的水平,另外 OSGi 也為系統(tǒng)架構(gòu)設(shè)計(jì)提供了更大的靈活性,使得我們開(kāi)發(fā)出像 Eclipse 那樣插件化的平臺(tái)系統(tǒng)不再遙不可及。

    相關(guān)主題

    • Eclipse.org:獲得有關(guān) Eclipse 的更多詳細(xì)資料。
    • Equinox:獲得有關(guān) Equinox 框架的更多詳細(xì)資料。
    • OSGi Alliance Service Platform:了解更多關(guān)于 OSGi 的信息,包括 OSGi Release 4 規(guī)范等信息。
    • Help – Eclipse SDK:獲得在 Eclipse 下進(jìn)行開(kāi)發(fā)的詳細(xì)幫助文檔。
    • “Eclipse 平臺(tái)入門(mén) -- 使用 Eclipse 插件來(lái)編輯、編譯和調(diào)試應(yīng)用程序”(developerWorks,2004 年 2 月):本文為您提供關(guān)于 Eclipse 平臺(tái)的概述,包括其起源和體系結(jié)構(gòu)。
    • “了解 Eclipse 插件如何使用 OSGi”(developerWorks,2006 年 9 月):闡明了 Eclipse 與 OSGi 的關(guān)系,還解釋了 OSGi manifest.mf 文件選項(xiàng)以及通過(guò) Eclipse 提供的添加項(xiàng)。
    • “基于 OSGi 的面向服務(wù)的組件編程”(developerWorks,2007 年 8 月):本文介紹了基于 OSGi 開(kāi)發(fā)一個(gè)應(yīng)用程序的過(guò)程,讀者可以學(xué)習(xí)如何基于 OSGi 開(kāi)發(fā)自己的應(yīng)用。
    • “探索 OSGi 框架的組件運(yùn)行機(jī)制”(developerWorks,2008 年 7 月):本文介紹了 OSGi 框架中的組件(Bundle)的運(yùn)行機(jī)制,并結(jié)合實(shí)際示例加以說(shuō)明。
    • developerWorks Eclipse 技術(shù)資源中心:這里匯集了大量和 Eclipse 開(kāi)發(fā)平臺(tái)相關(guān)的技術(shù)文章和教程。
    • developerWorks Java 技術(shù)專(zhuān)區(qū):這里有數(shù)百篇關(guān)于 Java 編程方方面面的文章。
    • 下載?Eclipse。
    • 下載?Equinox OSGi 框架。

    from:https://www.ibm.com/developerworks/cn/education/opensource/os-eclipse-osgi/index.html?

    總結(jié)

    以上是生活随笔為你收集整理的使用 Equinox 开发 OSGi 应用程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    亚洲黄色免费在线看 | 在线观看色视频 | 国产日产在线观看 | 月丁香婷婷 | 在线韩国电影免费观影完整版 | 成人三级av | 亚洲一区免费在线 | 五月综合激情婷婷 | 中国一级片在线播放 | 激情视频综合网 | av电影在线观看完整版一区二区 | 亚洲精品国产自产拍在线观看 | www91在线观看 | 在线观看免费视频你懂的 | 色久天 | 久久极品| 97电影院在线观看 | 在线视频一二区 | 天天干国产 | 亚洲综合一区二区精品导航 | 国产在线污| 国产精品18久久久久久不卡孕妇 | 国产一级免费观看视频 | 992tv成人免费看片 | 国产精品一区二区三区视频免费 | 欧美在线视频第一页 | 99av在线视频 | 日韩欧美精品一区二区三区经典 | 日韩精品一区二区三区中文字幕 | av在线免费在线 | 日韩中文字幕视频在线 | 国产成人精品一区在线 | 久久午夜免费观看 | bayu135国产精品视频 | 91看片网址| 中文字幕免费高清在线观看 | 天天综合网 天天 | 国产91精品久久久久 | 久久精品久久精品久久39 | 在线a人片免费观看视频 | 国产色啪 | 国产精品网站一区二区三区 | 2019中文在线观看 | 日韩精品视频第一页 | 久久免费黄色大片 | 黄色日批网站 | av一区在线播放 | 国产最新在线视频 | 欧美日韩不卡在线视频 | 久久99精品久久久久久 | 国产福利在线免费 | 免费中文字幕视频 | 天天色天天射综合网 | 美女视频黄,久久 | 久草线 | 免费国产在线精品 | 综合婷婷久久 | 丁香5月婷婷 | 99视频在线免费观看 | 日韩欧美在线观看一区二区三区 | 精品久久五月天 | 毛片在线播放网址 | 亚洲精品中文字幕视频 | 亚洲一级黄色大片 | 国产成人黄色 | 欧美孕交vivoestv另类 | 探花视频免费在线观看 | 色综合天天色综合 | 91看片在线播放 | 五月婷香蕉久色在线看 | 国产不卡av在线播放 | 国产剧情久久 | 国产我不卡 | 丁香电影小说免费视频观看 | av免费在线观看1 | 色婷婷一| 人人cao| 成人av影视观看 | 99婷婷| 色婷婷激情综合 | 色综合久久久久综合体 | 午夜视频在线观看一区 | 久二影院| 爱情影院aqdy鲁丝片二区 | 国产精品免费视频久久久 | 国产高清不卡在线 | 美女国产精品 | 操操操日日 | 97精品一区 | 五月天最新网址 | 一区二区中文字幕在线播放 | av成人在线电影 | 一本—道久久a久久精品蜜桃 | 91九色视频在线播放 | 超碰午夜| 国产福利精品在线观看 | 中文字幕一区在线观看视频 | 国产精品理论片在线播放 | 亚洲精品久久久久久中文传媒 | 欧美亚洲精品一区 | 国产精品video爽爽爽爽 | 99国产精品 | 一区二区三区免费在线 | 久久久久久久久久久久亚洲 | 欧美日韩国产一区二区三区在线观看 | 在线免费三级 | 色网站免费在线观看 | 中文在线字幕免费观看 | 天天干,天天射,天天操,天天摸 | 久久在线精品 | 狠狠色丁香久久婷婷综 | 国产96精品 | 国产伦理一区 | 日本精品va在线观看 | 久久 亚洲视频 | 九九热视频在线免费观看 | 麻豆免费视频观看 | 国产精品成人久久久久 | 日韩高清三区 | 99这里只有久久精品视频 | 玖玖视频在线 | 91av视频在线观看免费 | av导航福利 | 亚洲精品1234区 | 日免费视频 | 国产99久久精品一区二区300 | 福利一区二区在线 | 操操操夜夜操 | 最新在线你懂的 | 久久人人97超碰com | 17videosex性欧美 | 在线免费视频一区 | 国产精品夜夜夜一区二区三区尤 | 亚洲精品网址在线观看 | 天天摸夜夜操 | 午夜精品久久久99热福利 | 久久乱码卡一卡2卡三卡四 五月婷婷久 | www.com在线观看 | 麻豆传媒在线视频 | 国产精品一区二区你懂的 | 天天操天天射天天 | 久草在线最新 | 蜜臀久久99静品久久久久久 | 手机在线看永久av片免费 | 亚洲欧美国产精品久久久久 | 国产精品免费不卡 | 免费视频二区 | 天天插天天| 久久超碰免费 | 欧美日韩在线精品一区二区 | 日韩精品一区二区三区免费视频观看 | 久久在线视频在线 | 青青河边草免费 | 精品色999 | 久久社区视频 | 一区二区欧美激情 | 狠狠88综合久久久久综合网 | 久久久 精品 | 午夜久久福利影院 | 国产精品久久网站 | 亚洲欧洲国产视频 | 久草在线视频在线观看 | 国产精品久久久久久a | 久草在线视频首页 | 美女黄网久久 | 免费在线观看av | 免费在线观看日韩视频 | 国产视频久 | 日韩精品免费专区 | 蜜臀久久99精品久久久酒店新书 | 最近高清中文在线字幕在线观看 | 日本女人的性生活视频 | 久久久亚洲电影 | 日韩三级一区 | 亚洲高清在线精品 | 欧美a性| 免费看的黄色小视频 | 一区二区欧美在线观看 | 在线免费黄 | 国产美女被啪进深处喷白浆视频 | 久碰视频在线观看 | 九九在线播放 | 国产一级免费av | 亚洲综合欧美日韩狠狠色 | a级成人毛片 | 欧洲精品在线视频 | 日韩在线视频一区 | 麻豆果冻剧传媒在线播放 | 久久99操| 日韩免费看 | 成人黄色在线观看视频 | 国产日韩欧美在线免费观看 | 日日夜夜天天综合 | 美女福利视频一区二区 | 午夜av在线电影 | av观看免费在线 | 99热九九这里只有精品10 | 一区二区三区国产欧美 | 色婷婷国产精品 | 亚洲精品福利在线观看 | 久av在线| 韩国视频一区二区三区 | 国产精品久久久视频 | 四虎成人在线 | 91成人免费看 | 日日夜夜网站 | 国产91在线 | 美洲 | 欧美aaaxxxx做受视频 | 免费av 在线| 黄色国产在线观看 | 久久污视频| 亚洲精品中文在线 | 性色av免费看 | 国产高清视频在线免费观看 | 日韩在线视频免费看 | 激情电影在线观看 | 四虎影视精品成人 | 欧美一级性视频 | 中文av日韩 | 日韩av电影免费观看 | 国产91大片 | 日韩免费电影在线观看 | 99久久这里有精品 | 国产视频69 | 免费又黄又爽视频 | 99久久精品国产网站 | 国产一区观看 | 97精品国产97久久久久久 | 国产中年夫妇高潮精品视频 | 欧美精品黑人性xxxx | 国产成人精品av在线观 | 久久99亚洲精品久久久久 | 91精品国产99久久久久久红楼 | 在线观看黄色免费视频 | 视频在线观看一区 | 天天操夜夜摸 | 日韩中文字幕第一页 | 久久精品在线视频 | 欧美一级片 | 欧美韩日精品 | 欧美视频日韩 | 亚洲激情综合 | 中文字幕超清在线免费 | 91精品久久久久久综合乱菊 | 亚州国产精品视频 | 99久久精品免费看国产免费软件 | 亚洲精品伦理在线 | 99热这里| 久久激情片 | 亚洲无毛专区 | 成人欧美一区二区三区黑人麻豆 | 欧美精品v国产精品v日韩精品 | 天天综合视频在线观看 | 久久国产精品视频 | 欧美另类人妖 | 美女久久久久久久 | 亚洲国产精品久久久久婷婷884 | 国产日本三级 | 五月综合激情婷婷 | 久久久久久久国产精品视频 | 99久热在线精品视频 | 精品人人人 | 国产理伦在线 | 碰超在线 | 久久精品一区二区三区国产主播 | 丁香网婷婷 | 免费男女羞羞的视频网站中文字幕 | 中文字幕一区二区三区在线播放 | 日韩在线观看你懂得 | 国产精品久久久久久一区二区三区 | 色综合小说 | 91人人人 | 国产色视频123区 | 天天搞天天干 | a视频在线播放 | 五月激情久久 | 国产天天综合 | 国产精品久久久久久一区二区 | 日韩黄色软件 | 亚洲欧美日韩中文在线 | av免费看网站 | 久久伊人操 | 国产精品毛片久久久久久久 | 97超碰人人澡人人爱学生 | 四虎成人免费观看 | 国产亚洲精品久久久久久网站 | 免费在线观看成人小视频 | 99久久精品免费视频 | 久久久精品国产免费观看一区二区 | 日本一区二区三区免费看 | 国产精品s色 | 国产理论一区二区三区 | 欧美色图狠狠干 | 在线精品视频免费播放 | 手机成人免费视频 | 在线观看av中文字幕 | 日韩一区二区免费在线观看 | 日韩三级视频在线观看 | 国产精品一区二区果冻传媒 | 久久成人麻豆午夜电影 | 97电影院网 | 色婷婷欧美| 看片的网址| 国产高潮久久 | 欧美亚洲国产一卡 | 人人爱人人爽 | 在线看片视频 | 免费看成人a| 亚洲精品99久久久久中文字幕 | 国产精品18久久久 | 91在线精品播放 | 亚洲日韩欧美一区二区在线 | 一区在线免费观看 | 色婷婷av一区 | 久久精品人 | 欧美国产日韩一区二区三区 | 国产啊v在线观看 | 在线91av| 亚洲在线观看av | 韩日视频在线 | 婷婷色视频 | 欧美91精品 | 欧美一区二区三区特黄 | 在线免费中文字幕 | 日韩精品一区二区三区高清免费 | 免费日韩一区二区三区 | 亚洲乱码精品久久久 | 日韩女同av | 最近中文字幕免费观看 | 国产精品精品国产色婷婷 | 97超碰人人 | 婷婷国产一区二区三区 | 欧美一区在线观看视频 | 香蕉网在线观看 | 日韩美一区二区三区 | 婷香五月 | 色婷婷在线播放 | 亚洲电影影音先锋 | 狠狠狠色丁香综合久久天下网 | 国产精品毛片久久久久久久久久99999999 | 日韩爱爱网站 | 丁香色婷婷 | 国产精品免费不卡 | 人人干天天射 | 国产另类av | 精品久久久免费视频 | 韩国av免费看 | 午夜视频在线观看一区 | 国产精品大片在线观看 | 日本久久视频 | 免费在线激情电影 | 日韩高清精品免费观看 | 国产精品永久久久久久久www | 91精品国产乱码在线观看 | 国产精品乱码久久 | 色视频 在线 | 亚洲在线视频免费观看 | 精品久久久久久国产偷窥 | 天天干夜夜想 | 婷婷精品国产欧美精品亚洲人人爽 | 99久久www | 黄色avwww| 国产精品伦一区二区三区视频 | 欧美在线日韩在线 | 欧美高清成人 | 中文在线| 久久久久久久久久久免费 | 成人亚洲免费 | 精品久久久久亚洲 | 最近最新mv字幕免费观看 | 黄色亚洲大片免费在线观看 | av电影在线播放 | 午夜av一区二区三区 | 国产精品a级 | 亚洲国产成人高清精品 | 在线播放一区二区三区 | 欧美片一区二区三区 | 久久久噜噜噜久久久 | 在线视频你懂得 | 国产一区二三区好的 | 中文字幕第一页在线 | 亚洲在线色 | 亚洲欧美色婷婷 | 欧美性爽爽 | 国产色久| 91网站在线视频 | 在线亚洲人成电影网站色www | 久久久久久高潮国产精品视 | 超级碰99 | 91激情视频在线 | 在线免费观看黄色大片 | 亚洲国产日韩一区 | 日韩欧美xxxx | 在线观看亚洲精品 | 国产网站在线免费观看 | 麻豆国产网站入口 | 亚洲精品国产精品乱码在线观看 | 久久久免费看片 | 亚洲在线免费视频 | 96精品视频 | 九九九在线观看 | 久久成年人视频 | 在线看岛国av | 久久99亚洲精品久久久久 | 亚洲伊人av| 久久久久中文字幕 | 五月天伊人网 | 97在线视 | 91天堂影院 | 国产97色 | 九九九热精品 | 97人人爽| 一区免费观看 | 国产在线 一区二区三区 | 在线观看av不卡 | 亚洲国产成人久久 | 国产99久久九九精品免费 | 久久国产手机看片 | 一区二区三区福利 | 日韩婷婷| 九九九在线观看视频 | av一级在线 | 在线免费观看视频你懂的 | 国产精品18久久久久久久网站 | 欧美日韩啪啪 | 欧美日韩亚洲在线 | 四虎成人免费影院 | 色播99 | 久久五月天婷婷 | 国产精品 999 | 中文字幕日韩国产 | 欧美日韩国产一区二区三区在线观看 | 激情视频在线观看网址 | 一区二区高清在线 | 日本三级吹潮在线 | 色五婷婷 | 狠狠色丁香久久婷婷综合_中 | 亚洲精品久久久久中文字幕m男 | 成人黄色电影在线播放 | 日韩免费视频观看 | 欧美久久久久久久久久 | 久久国产精品一区二区 | 中文字幕一区二区三区四区在线视频 | 韩国av免费观看 | 日韩草比 | 久久不见久久见免费影院 | 亚洲成人家庭影院 | 免费精品久久久 | 国产精品中文字幕av | 国产在线观看免费观看 | 亚洲狠狠丁香婷婷综合久久久 | 欧美黄在线 | 国产成在线观看免费视频 | 日韩极品在线 | 国产一区免费观看 | 成人黄色小说在线观看 | 日日操日日干 | 天天操天天射天天舔 | 国产一区二区精品久久 | 国产xxxx| 九九综合在线 | 美女国产精品 | 日韩在线视频一区 | 欧美 日韩精品 | 成年人在线免费视频观看 | 国产欧美精品一区二区三区四区 | 瑞典xxxx性hd极品 | 久久图| 国产精品三级视频 | 国产精品入口a级 | 亚洲热视频 | 97夜夜澡人人双人人人喊 | 黄色影院在线免费观看 | 久草爱 | 国产高清一级 | 久草在线视频在线 | 黄色毛片视频免费观看中文 | 蜜臀av夜夜澡人人爽人人桃色 | 欧美日韩一区二区三区在线观看视频 | 亚洲每日更新 | 天天操导航 | 免费三级黄色 | 国产精品男女视频 | 国产黑丝袜在线 | 亚洲在线a | 亚洲成人高清在线 | 韩日视频在线 | 国产精品手机播放 | av中文字幕不卡 | 日韩欧美视频免费观看 | 亚洲黄色在线免费观看 | 久久欧美综合 | 欧美成人精品欧美一级乱黄 | 中文字幕乱码电影 | 一级片在线 | 五月婷婷导航 | 国产亚洲一区二区在线观看 | 黄色三级免费网址 | 韩国三级一区 | 国产精彩视频一区二区 | 亚洲日本在线视频观看 | 激情av在线播放 | 激情五月网站 | 99久热在线精品 | 日韩国产精品毛片 | 亚洲蜜桃在线 | 免费视频一区二区 | 中文字幕日韩伦理 | 亚洲激情国产精品 | 国产精品久久久毛片 | 久久综合久久综合这里只有精品 | 国产美女久久 | 欧美一级免费 | 一区二区伦理电影 | 免费的国产精品 | 亚洲国产中文字幕 | 欧美99热 | 久久福利小视频 | 欧洲一区精品 | 国产91成人在在线播放 | 亚洲精品免费播放 | 黄色福利网站 | 最近中文字幕久久 | 国产午夜精品av一区二区 | 日批视频在线 | 91麻豆精品国产91久久久久久 | 亚洲在线色 | 国产午夜精品一区二区三区在线观看 | 美女视频黄免费 | 亚洲欧美综合精品久久成人 | 在线观看中文字幕av | 精品欧美小视频在线观看 | 久久亚洲日本 | 高清一区二区三区av | 免费在线观看国产精品 | 精品国产一区二区三区四区vr | 色国产精品一区在线观看 | 欧美精品乱码久久久久久 | 中文在线8资源库 | 国产女人18毛片水真多18精品 | 久久久午夜视频 | 欧美大jb| 在线观看www视频 | 免费亚洲片 | 亚洲美女精品视频 | 丁香婷婷久久久综合精品国产 | 最近中文字幕在线播放 | 国产亚洲无 | 韩日三级av | 美女av在线免费 | 日日夜夜国产 | 欧洲一区二区三区精品 | www.91av在线| 国产97碰免费视频 | 91超国产| 亚洲91av| 免费看亚洲毛片 | 日韩一区二区三区在线观看 | 伊人久久精品久久亚洲一区 | 日韩亚洲国产中文字幕 | 成人资源站 | 波多野结衣视频在线 | 国产一区二区观看 | 国产v在线播放 | 国偷自产视频一区二区久 | 一区二区视频电影在线观看 | 成人黄色影片在线 | 日韩久久精品一区二区三区 | 特级西西444www大胆高清无视频 | 婷婷色狠狠 | 狠狠色丁香久久婷婷综合五月 | 国产尤物在线观看 | 天天天天色综合 | 国产美女精彩久久 | 成人黄色免费在线观看 | 日本成人中文字幕在线观看 | av免费网站在线观看 | a级国产乱理论片在线观看 伊人宗合网 | 91精品国产91p65 | 美女网站黄免费 | 国产高清永久免费 | 久久久蜜桃 | 日韩国产在线观看 | 91黄色小网站 | 成人a免费| 在线免费观看羞羞视频 | 亚洲国产精品推荐 | 欧美日在线观看 | 99av在线视频 | 亚洲精品系列 | 一区二区三区中文字幕在线观看 | 国产专区一 | 久久一二三四 | 久久精品视频免费 | 在线免费观看不卡av | 久久1电影院 | 国产亚洲婷婷免费 | 99精品免费视频 | 国产成人精品午夜在线播放 | av中文字幕在线看 | 日韩网站在线看片你懂的 | 97在线免费观看视频 | 九九涩涩av台湾日本热热 | 免费能看的av | 日韩免费观看一区二区 | 国产精品一区二区 91 | 又爽又黄在线观看 | 国产精品无av码在线观看 | 亚洲精品乱码久久久久久按摩 | 日韩精品视频久久 | 玖玖爱国产在线 | 亚洲1区在线 | 日本三级不卡视频 | www.狠狠色.com | 欧美日韩不卡一区二区三区 | 久福利| 色综合久久久久综合 | 欧美国产日韩一区 | 精品国产资源 | 午夜婷婷在线观看 | 国产欧美精品在线观看 | 久久在线观看视频 | 国产精品久久久久毛片大屁完整版 | 国产日韩在线播放 | 麻豆久久| 日韩mv欧美mv国产精品 | 精品亚洲午夜久久久久91 | 免费亚洲一区二区 | 91精品国产福利 | 国产精品麻豆视频 | 亚洲欧洲美洲av | 国产成人在线网站 | 五月天婷婷丁香花 | 中日韩免费视频 | 国产美女精品人人做人人爽 | 成人欧美一区二区三区黑人麻豆 | 国产999在线 | 久草爱 | 久久99日韩 | 国产精品密入口果冻 | 精品视频www | 亚洲精品在线免费 | 在线观看av国产 | 国内免费的中文字幕 | 免费观看十分钟 | 欧美成人69av | 日韩大片在线看 | 在线三级av | 日韩中文字幕a | 91av中文字幕 | 婷婷丁香九月 | 99久久这里只有精品 | 六月丁香激情综合色啪小说 | 欧美二区三区91 | 中文字幕av播放 | 久久综合九色欧美综合狠狠 | 丝袜美腿在线 | 五月天视频网站 | 久久99久久99精品免视看婷婷 | 成年人在线免费看视频 | 激情开心| 国产在线中文字幕 | 久久久av电影 | 91精品视频免费看 | 国语自产偷拍精品视频偷 | 中文字幕资源网 国产 | 黄色三级网站 | 国产人成免费视频 | 国产区精品| 国内精品久久久久影院优 | 久久伊人八月婷婷综合激情 | 中文字幕中文字幕在线中文字幕三区 | 婷婷激情在线观看 | 亚洲欧美日韩一级 | 国产精品麻豆99久久久久久 | 成人在线免费观看视视频 | 欧美另类高潮 | 久久理论影院 | 国产成人性色生活片 | 精品美女久久久久久免费 | 亚洲中字幕 | 亚洲日本欧美 | 中文字幕高清在线 | 麻豆国产在线播放 | 精品免费视频123区 午夜久久成人 | 久久艹综合 | 久久久麻豆视频 | 欧美一级激情 | 国产免费视频在线 | 超碰在线cao | 黄色小说在线免费观看 | 国产精品欧美激情在线观看 | 最近中文字幕久久 | 色噜噜日韩精品一区二区三区视频 | 成av在线| 在线免费av网站 | 97国产一区二区 | 午夜视频不卡 | 一区二区三区www | 91精品网站在线观看 | 亚洲国产精品视频 | 黄色免费网站下载 | 亚洲精品综合久久 | 综合久久久久久久久 | 国产精品午夜在线 | 久精品在线 | 黄色片网站av | 天天爱天天射天天干天天 | 久久久国产精品一区二区三区 | 亚洲精品观看 | 日本黄色黄网站 | 免费观看性生活大片3 | 999国内精品永久免费视频 | 五月婷婷一区二区三区 | 97成人精品区在线播放 | 成人9ⅰ免费影视网站 | 国产精品久久久久久久久久久久久久 | 2024av| 男女拍拍免费视频 | 欧美日韩中文在线观看 | 97视频在线播放 | 欧美色综合 | 欧美性春潮| 日韩成人欧美 | 在线观看午夜av | 久草在线免 | 一区二区三区在线观看免费 | 欧美日韩国产在线观看 | 99视频免费在线观看 | 亚洲精品tv久久久久久久久久 | 最新影院| 成人一区影院 | 欧美久久久久久久 | 免费又黄又爽的视频 | 一级黄色免费 | 久久在线免费 | 日本中出在线观看 | 91在线观看高清 | 91麻豆福利 | 中文字幕在线观看不卡 | 国产无限资源在线观看 | 国产精品都在这里 | 日韩理论电影在线 | 极品中文字幕 | 91久久精品一区二区三区 | 日韩黄色免费 | 日本精a在线观看 | 高清在线观看av | 欧美精品久久人人躁人人爽 | 在线观看免费日韩 | 中文资源在线官网 | 99热在线观看免费 | 中文字幕中文字幕中文字幕 | 国产精品激情 | 国产999精品 | 国产精品久久久av | 精品国产免费看 | 国产亚洲一级高清 | 日日干天天射 | 久青草视频在线观看 | 少妇高潮流白浆在线观看 | 99性视频 | 国产美女精品久久久 | 国产精品美女久久久久久久 | 成年人天堂com | 亚洲精品小视频在线观看 | 免费视频国产 | 久久国产电影 | 操一草| 午夜精品久久久久久久久久久久 | 久久国产精品99久久久久久丝袜 | 国内精品福利视频 | 久久精品99国产 | 国产玖玖精品视频 | 不卡av在线 | 亚洲精品久久久久久久蜜桃 | 午夜美女网站 | 成年人视频在线免费播放 | 在线成人国产 | 黄色avwww | 亚洲视频 视频在线 | 波多在线视频 | 国产亚洲视频在线免费观看 | 国产精品美女久久久久久久久久久 | 黄p网站在线观看 | 精品中文字幕在线 | www91在线观看 | 日韩av影片在线观看 | 国产手机在线精品 | 欧美日韩一区久久 | 91麻豆精品久久久久久 | 欧美性爽爽 | 97超碰精品 | 日韩欧美91| 久久久久北条麻妃免费看 | 久久99热精品 | 久久免费国产精品 | 美国av片在线观看 | 色噜噜狠狠色综合中国 | 欧美不卡视频在线 | 国产一级精品视频 | 国产中的精品av小宝探花 | 国产精品一区久久久久 | 99视频久 | 91精品久久久久久综合乱菊 | 狠狠伊人| 日韩一区二区三 | 亚洲最新视频在线 | 看片黄网站 | 久久99免费 | 日韩免费视频在线观看 | 日韩一区二区三 | 2020天天干天天操 | 欧美极品一区二区三区 | 国产精品第54页 | 日本精品一区二区三区在线播放视频 | 欧美一区二区精品在线 | 韩国精品在线观看 | 99久免费精品视频在线观看 | 国产成人久久av977小说 | 亚洲综合色婷婷 | 日本不卡一区二区 | 91成人免费 | 国产精品 欧美 日韩 | 午夜国产福利在线 | 日韩精品短视频 | 国产精品久久久久亚洲影视 | 2023年中文无字幕文字 | www.久久久| 亚洲高清久久久 | 色综合久久五月天 | 久久精品超碰 | 欧美激情视频一二区 | 国产成人61精品免费看片 | 黄色毛片视频 | 国产精品白丝jk白祙 | 亚洲在线视频免费 | 超碰人人av | 夜夜夜夜夜夜操 | 一区二区伦理 | 黄污视频网站大全 | 欧美极度另类 | 久久精品一二三区 | 午夜精品一区二区国产 | 久久99热这里只有精品 | 亚洲一级理论片 | 中文字幕免费高清av | 国产美女精品人人做人人爽 | 久草精品视频在线观看 | 91av观看 | 色资源二区在线视频 | 国产 日韩 在线 亚洲 字幕 中文 | 丁香久久激情 | 久久精国产 | 国产精品99久久99久久久二8 | 97理论片 | 国产一卡二卡四卡国 | 成人av网站在线 | 日本xxxx.com | 免费亚洲黄色 | 成人综合免费 | 免费视频久久久久 | 在线影院av | 91亚洲永久精品 | 午夜视频在线观看网站 | 免费av在线网 | 高清在线一区二区 | 久久成熟 | 午夜丰满寂寞少妇精品 | 国产在线91精品 | 国产视频1区2区3区 久久夜视频 | 国产五月婷 | 91精品视频一区 | 丁香婷婷成人 | 片网站| 狠狠操操操 | 天天在线免费视频 | 黄色在线观看网站 | 中文字幕第 | 黄色的视频网站 | 国产小视频你懂的 | 在线导航av | 日本中文字幕视频 | 久久草在线免费 | 一区免费观看 | 久久精品欧美一区 | 欧美整片sss| 摸bbb搡bbb搡bbbb | 成人黄色电影在线观看 | 日韩一区二区在线免费观看 | 国产 在线 日韩 | 成人免费看片网址 | 欧美一区免费在线观看 | 免费的黄色av | 麻豆果冻剧传媒在线播放 | 成人一区二区在线观看 | 国产精品99久久久精品 | 久久亚洲欧美日韩精品专区 | 黄色电影网站在线观看 | 久影院 | 精品久久久久久久久久久久久 | 18+视频网站链接 | 色天天综合网 | 97视频在线观看成人 | 六月丁香伊人 | 久久久精品福利视频 | 99久久婷婷| 国产精品夜夜夜一区二区三区尤 | 激情久久影院 | 人人爽网站| 国产精品九色 | 夜夜爱av | 日韩av一区在线观看 | 国产视频在线观看免费 | 欧美成人h版在线观看 | 狠狠狠狠狠狠天天爱 | 99久久婷婷国产综合精品 | 婷婷久久丁香 | 九九九九九九精品 | 亚洲黄色在线免费观看 | 黄色成人影院 | 国产女做a爱免费视频 | 视频一区二区精品 | 免费观看一区二区三区视频 | 日本精品久久久久久 | 国产高清不卡在线 | 九九九毛片 | 欧美在线观看视频一区二区 | 久久综合狠狠综合 | 国产成人久久 | 久草在线费播放视频 | 亚洲国产高清在线观看视频 | 久久免费电影网 | 在线三级av | 九九视频免费观看视频精品 | 人人射人人爱 | 国产成人三级一区二区在线观看一 | 精品久久久久久久久亚洲 | 中文字幕专区高清在线观看 | 91精品国产91久久久久久三级 | 久久99国产综合精品免费 | 天天干夜夜爱 | 免费观看mv大片高清 | 亚洲电影成人 | 久久精品79国产精品 | 日本中文字幕电影在线免费观看 | 精品一区二区在线免费观看 | 国产精品九九久久99视频 | 一区二区精品在线 | 亚洲视屏在线播放 | 日韩欧美在线第一页 | 免费在线一区二区 | 五月天中文字幕 | 久久精品国产成人精品 | 在线观看黄色小视频 | 一区二区三区国产欧美 | 高清av网 | 久久久影视 | 国产在线精品一区二区 | 人人要人人澡人人爽人人dvd | 日日操日日 | 日韩免费看的电影 | 久久久国产一区二区三区 | av黄色成人| 国产一区成人在线 | 蜜臀av.com | 亚洲精品乱码 | 欧美精品国产综合久久 | 中文字幕一二三区 | 国产一区二区三区高清播放 | 97av精品| 99精品色| 婷婷av色综合| 婷婷在线五月 | 99婷婷狠狠成为人免费视频 | 欧美高清视频不卡网 | 91在线蜜桃臀 | 99视频在线精品免费观看2 | 国产黄在线免费观看 | 久久99精品国产麻豆宅宅 | 91亚洲在线 | www.香蕉 | 中文字幕高清视频 | 日日夜夜人人精品 | 国产精品成人免费 | 欧美久久综合 | 国色天香av| 国产无区一区二区三麻豆 | 夜夜操网站 | 四虎视频 | 91在线观| 久久亚洲电影 | .国产精品成人自产拍在线观看6 | 91视频麻豆视频 | 视频在线99re | 久久久久免费精品视频 | 国产日产欧美在线观看 | 国产精品不卡在线 |