日韩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ò),歡迎將生活随笔推薦給好友。

    久久er99热精品一区二区 | 国产在线精品一区二区三区 | 麻豆久久久 | 九色porny真实丨国产18 | 久久精品超碰 | 97av视频在线| 国产亚洲成av人片在线观看桃 | 日本公妇在线观看高清 | 人人天天夜夜 | 国产99一区二区 | 黄色国产成人 | 国产精品视频免费 | 午夜久久久久久久久 | 五月天中文字幕mv在线 | 国产综合福利在线 | 99热手机在线观看 | 国产精品va | 在线www色 | 亚洲春色综合另类校园电影 | 97精品国产97久久久久久 | 国产亚洲视频中文字幕视频 | 久久狠狠一本精品综合网 | 日日干天天插 | 丁香在线观看完整电影视频 | 国内精品久久久久久 | 天天干夜夜操视频 | 蜜桃传媒一区二区 | 制服丝袜在线 | 91精品国产综合久久福利不卡 | 色妞色视频一区二区三区四区 | 久久免费的视频 | 天天看天天干 | av一本久道久久波多野结衣 | 久久人人爽人人爽人人 | 亚洲最新在线视频 | 五月视频 | 欧美久久综合 | 黄色综合 | 久久99亚洲热视 | 成年人免费av网站 | 日韩综合精品 | 久久国产成人午夜av影院宅 | 久久国产麻豆 | 99久热在线精品视频成人一区 | 日韩有色| 一级黄色片在线免费看 | 免费av一级电影 | 久久久久久久久亚洲精品 | 国产午夜三级一区二区三桃花影视 | 天天操夜夜想 | 日韩成人欧美 | 99国产精品久久久久久久久久 | 亚洲精品国产成人av在线 | 青青草视频精品 | 精品国产伦一区二区三区观看体验 | 成人网看片 | 精品国产一区二区三区久久久 | 99视频精品在线 | 激情综合网五月 | 97超碰精品 | 一本一本久久a久久精品综合 | 91av色| 91免费观看网站 | 2020天天干夜夜爽 | www色网站| 麻豆精品视频在线观看免费 | 国内精品久久久久影院日本资源 | 日本三级在线观看中文字 | 97电影手机版 | 奇米影视四色8888 | 狠狠色香婷婷久久亚洲精品 | 欧美日韩一区二区在线观看 | 91重口视频 | 欧美日韩国产综合一区二区 | 一本一道久久a久久精品 | 偷拍区另类综合在线 | 久久久久国产一区二区三区四区 | 国产精品久久嫩一区二区免费 | av线上看 | 成人在线免费小视频 | 免费在线黄色av | 国产成人精品一区二三区 | 开心丁香婷婷深爱五月 | 国内精品久久久久影院一蜜桃 | 欧美伦理一区二区三区 | 国产精品福利在线播放 | 国产精品一区二区久久国产 | 久久久久国产成人精品亚洲午夜 | 欧美 亚洲 另类 激情 另类 | 久久精品毛片基地 | www.777奇米 | 亚洲国产视频a | 97超碰资源网 | 人人爽人人香蕉 | 在线视频 成人 | av在线播放观看 | 日韩av成人| 精品久久久久久久久久久院品网 | 久久免费资源 | 欧美激情第一区 | 丁香五婷 | 久草热视频 | 91在线公开视频 | 日本精品久久久久中文字幕 | 男女视频国产 | 国产亚洲一区二区在线观看 | 亚洲人毛片 | 日韩在线观看中文字幕 | 五月激情丁香图片 | 免费视频三区 | wwwwww国产 | 久草在线最新 | 五月婷婷爱 | 精品久久片 | 久草视频国产 | 国产亚洲精品xxoo | 日本黄色一级电影 | 国产精品视频永久免费播放 | 国产一级黄色免费看 | 中文字幕乱在线伦视频中文字幕乱码在线 | 最新日韩在线观看 | 国产精品日韩在线观看 | 九九热有精品 | 久久黄色免费观看 | 91成人免费看片 | 免费看成年人 | 亚洲精品国产自产拍在线观看 | 午夜精品久久 | 69国产盗摄一区二区三区五区 | av福利网址导航大全 | 精品久久久久久国产91 | 五月天激情视频 | 亚洲香蕉在线观看 | 国产a级片免费观看 | 日韩精品在线观看视频 | 免费看成人 | 91精品1区| 一区二区三区高清在线 | 午夜精品久久久久久久99 | 婷婷网站天天婷婷网站 | 综合天堂av久久久久久久 | 国产精华国产精品 | 精品uu| 欧美一二区视频 | 日韩av在线一区二区 | 天堂网一区 | 视频在线播放国产 | www天天操 | 日本黄色免费电影网站 | 免费看污网站 | 久久久久久黄色 | 中文字幕黄色网 | 天天操天天弄 | 久久爱992xxoo| 婷婷色在线视频 | 天天色天天综合网 | 欧美国产日韩在线观看 | 成人超碰97 | 国产精品久久久久久影院 | 97在线观看免费观看高清 | 亚洲国产精品成人va在线观看 | 国产欧美精品一区二区三区 | 日本中文字幕视频 | 久久艹国产视频 | 国产美女精彩久久 | 精品国产一区二区三区久久久蜜臀 | 日日碰狠狠添天天爽超碰97久久 | 亚洲少妇久久 | 五月天久久久久久 | 成人免费在线看片 | 天天草天天干天天 | 国产一区视频在线观看免费 | 久草精品视频 | 制服丝袜天堂 | 最近最新中文字幕视频 | 国产最新91 | 毛片网站在线看 | 国产日产精品一区二区三区四区的观看方式 | 国产精品尤物视频 | 久久不卡视频 | 香蕉视频日本 | 欧美91精品国产自产 | 日韩理论电影在线观看 | 国产一级h | 91九色在线播放 | 在线观看中文字幕第一页 | 亚洲精品国产综合99久久夜夜嗨 | 国产精品免费久久久久影院仙踪林 | 精品国产一区二区三区不卡 | 成人免费中文字幕 | 手机看片午夜 | 在线不卡中文字幕播放 | av片子在线观看 | 成人黄色资源 | 黄色一级在线视频 | 久久久久麻豆v国产 | 亚洲精品国产成人av在线 | 国产精品99视频 | 午夜久久影视 | 最近免费中文字幕大全高清10 | 在线视频麻豆 | 国产视频首页 | www·22com天天操 | 视频国产在线 | 在线免费av网 | 中文在线字幕观看电影 | 久久成人18免费网站 | 亚洲 中文字幕av | 久久精品免费播放 | 久草在线视频首页 | 一区二区不卡在线观看 | 久久婷婷影视 | 99热精品视 | 精品国产一区二区三区在线观看 | 中文字幕在线观看网址 | av网站免费线看精品 | 97视频人人澡人人爽 | 麻豆精品传媒视频 | 黄色a级片在线观看 | 丁香婷婷久久久综合精品国产 | 激情丁香婷婷 | 中文字幕在线视频免费播放 | 97视频人人免费看 | 中文字幕第一页在线视频 | 五月婷婷综合色拍 | 免费看片黄色 | 九九在线播放 | av女优中文字幕在线观看 | 91日韩免费 | 欧美一区三区四区 | 超碰电影在线观看 | 国产精品久久久久久久久久久久午 | 亚洲专区中文字幕 | 久久爱综合 | 久在线观看视频 | 国产一二区在线观看 | 精油按摩av| 手机av资源| 日本最新一区二区三区 | 亚洲国产剧情 | 伊人电影在线观看 | 麻花豆传媒mv在线观看网站 | 在线不卡的av | 国产精品com | 97超碰网| 在线之家免费在线观看电影 | 2019天天干夜夜操 | 国产一级久久 | 黄色免费av | 色综合天天综合 | 亚洲午夜精品在线观看 | 在线天堂亚洲 | 欧美激情奇米色 | 草草草影院 | 亚洲精品国产综合久久 | 麻豆视频一区二区 | 91麻豆精品国产91久久久使用方法 | 国产真实精品久久二三区 | 日韩美女久久 | 国产高清永久免费 | 日韩高清免费观看 | 欧美动漫一区二区三区 | 久久综合婷婷国产二区高清 | 探花视频免费在线观看 | 亚洲电影免费 | 国产视频一级 | 免费网站看v片在线a | 久久久久国产精品免费 | 国产日产精品一区二区三区四区的观看方式 | 国产综合91| 欧美日韩高清在线 | 国产麻豆精品在线观看 | 国产97碰免费视频 | 天天躁日日躁狠狠躁 | 五月天综合激情 | 国产手机精品视频 | 久久久精品国产一区二区 | 国产97视频 | 91视频久久久久久 | 五月香视频在线观看 | 国产精品免费久久久久影院仙踪林 | 狠狠狠色丁香综合久久天下网 | 日日骑 | 五月天激情视频 | 又长又大又黑又粗欧美 | 在线不卡中文字幕播放 | 成年人在线免费看片 | 日韩午夜电影网 | 日韩免费在线观看视频 | 欧洲在线免费视频 | 免费av网址在线观看 | 成 人 黄 色视频免费播放 | 99热这里是精品 | 91视频午夜 | 久久任你操 | 色偷偷人人澡久久超碰69 | 欧美日韩一级视频 | 成人福利在线播放 | 亚洲综合网站在线观看 | 精品久久久久久久久久岛国gif | 亚洲蜜桃在线 | 免费看成人 | 一级黄色片在线观看 | 麻豆传媒一区二区 | 欧美一区二区三区在线 | 黄色亚洲免费 | 又黄又爽又色无遮挡免费 | 中文字幕在线播放视频 | 国产精品美女久久久免费 | 国产高清在线一区 | 亚洲成人xxx | 国产精品久久久久av福利动漫 | 四虎成人av | 久久国产精品系列 | 国产精品自产拍在线观看桃花 | 久久久久久久久亚洲精品 | 黄色免费在线视频 | 水蜜桃亚洲一二三四在线 | 国产一区二区三区高清播放 | 久久精品伊人 | 一区二区三区高清在线 | 成人三级网站在线观看 | 日韩日韩日韩日韩 | 免费在线观看成人 | av免费片| 精品五月天 | 精品国产伦一区二区三区观看体验 | 99久久日韩精品视频免费在线观看 | 精品一区中文字幕 | 国产超碰97| 国产精品成人国产乱一区 | 亚洲精品激情 | 国产麻豆精品免费视频 | 国产精品久久久久影视 | 日韩av电影手机在线观看 | 亚洲国产中文字幕在线观看 | 在线视频亚洲 | 狠狠色伊人亚洲综合成人 | 成人资源在线播放 | 91女神的呻吟细腰翘臀美女 | 又色又爽的网站 | 欧美日韩精品区 | 久久久久久久久影院 | 超碰国产97| 亚洲女人天堂成人av在线 | 国产精品久久久久久久久免费看 | 日韩理论片在线 | 中文字幕最新精品 | 91麻豆免费看 | 亚洲涩涩一区 | 手机在线黄色网址 | 久久久www | 免费观看全黄做爰大片国产 | 久久久精品国产免费观看一区二区 | 在线精品视频免费观看 | 国产又粗又长又硬免费视频 | 91久久国产综合精品女同国语 | 超碰97免费在线 | 免费高清无人区完整版 | 婷婷五天天在线视频 | 免费三级影片 | 成人在线播放av | 成人久久久电影 | 中文字幕一区二区三区久久 | 国产亚洲精品久久久久久 | 免费激情在线电影 | 最近2019好看的中文字幕免费 | 99精品国产99久久久久久福利 | 国产午夜精品久久 | 亚洲精品网址在线观看 | 成年人在线看片 | 欧美另类交在线观看 | 国产午夜精品一区二区三区 | 成人国产电影在线观看 | 久久综合色天天久久综合图片 | japanesexxxxfreehd乱熟 | 久久草草热国产精品直播 | 久久精品8 | 精品一区二三区 | 亚洲1区在线 | 97精品国自产拍在线观看 | 在线天堂中文在线资源网 | 欧美先锋影音 | 日韩mv欧美mv国产精品 | 欧美日韩国产亚洲乱码字幕 | 久久精品国产精品亚洲 | 久久夜色精品国产欧美乱极品 | 亚洲成色| 国产91精品在线观看 | 国产精品一区二区在线观看 | 欧洲一区二区在线观看 | 狠狠狠色丁香婷婷综合久久88 | 在线中文字幕网站 | 国产亚洲综合性久久久影院 | 国产a国产a国产a | 最新黄色av网址 | 色婷婷狠狠五月综合天色拍 | 成人午夜电影网 | 9ⅰ精品久久久久久久久中文字幕 | 免费精品在线 | 国产精品久久久久久久久久久久午夜 | 国产小视频在线观看免费 | 午夜精品视频在线 | www国产一区| 一区二区精品在线 | 久久久性 | 深爱婷婷久久综合 | 最新中文字幕在线观看视频 | 午夜精品视频免费在线观看 | 国产精品1区2区 | 中文字幕亚洲欧美日韩2019 | 午夜视频免费在线观看 | 色综合天天综合 | 五月综合网站 | 天堂网av 在线 | 亚洲视频久久久久 | 国产原创av在线 | 国产精品久久久久久久久久久免费 | 日韩欧美视频一区二区 | 久久久999免费视频 日韩网站在线 | 日韩黄在线观看 | 九九热精品在线 | 亚洲精品在线看 | 国产精品一区二区久久久 | 日韩一区二区三区免费视频 | 亚洲视频在线免费看 | 福利精品在线 | www免费| 久久免费在线视频 | 狠狠干夜夜 | 天天综合网天天综合色 | 久久综合久久综合久久综合 | 久久麻豆视频 | 中文字幕在线一区二区三区 | 91日本在线播放 | 亚洲精品中文在线 | 久久久久久97三级 | 国产在线污 | 午夜性色 | 国产亚洲在线观看 | 成人久久免费 | 伊人在线视频 | 国产精品va最新国产精品视频 | 欧美热久久 | 欧美日韩在线播放 | 免费国产在线视频 | 欧美福利视频一区 | 久久九九免费视频 | 手机av在线网站 | 六月丁香综合 | 国产精品久久一区二区三区不卡 | 亚洲黄色片一级 | 91九色蝌蚪视频在线 | 2020天天干夜夜爽 | 国产免费观看久久 | 国产黄色精品在线观看 | 天天插视频 | 天天色天天射综合网 | 岛国av在线不卡 | 在线综合 亚洲 欧美在线视频 | 色多视频在线观看 | 日韩精品一区二区三区外面 | 亚洲精品在线一区二区三区 | 最新中文字幕在线播放 | 亚洲精品女 | 西西www4444大胆视频 | 午夜 久久 tv| 国产.精品.日韩.另类.中文.在线.播放 | 日韩欧美69 | 美女视频永久黄网站免费观看国产 | 天天激情综合 | 国产一区电影在线观看 | 三上悠亚在线免费 | 制服丝袜亚洲 | 久久精品艹 | 97综合在线 | www.操.com| 久久久久黄 | 97操操| 国产精品欧美久久久久三级 | 国产精品成人久久久 | 日韩欧美在线不卡 | 黄网站免费大全入口 | 狠狠色丁香 | 五月天免费网站 | 九九热免费在线观看 | 日韩中文字幕第一页 | wwxxx日本 | 亚洲永久精品一区 | 日韩免费看的电影 | 在线观看香蕉视频 | 国产精品区二区三区日本 | 欧美一级爽| 日本性xxxxx| 久久精品亚洲综合专区 | av动态图片| 丁香婷婷综合色啪 | 婷婷五天天在线视频 | 欧美日韩视频一区二区三区 | 日韩中文字幕在线看 | 久草在线在线精品观看 | 欧美视频在线观看免费网址 | 天堂av观看| 成人永久在线 | 四虎永久视频 | 亚洲精品网站在线 | 亚洲日韩中文字幕在线播放 | 又黄又爽又湿又无遮挡的在线视频 | 91丨九色丨高潮丰满 | 亚洲激情av| 久久精品资源 | 精品国产乱码久久久久久1区二区 | 亚洲三级性片 | 在线播放第一页 | 免费黄在线看 | 成人在线黄色电影 | 亚洲免费精品视频 | 婷婷色综合网 | 外国av网 | 麻豆传媒视频在线免费观看 | 国产精品v a免费视频 | 亚州精品在线视频 | 欧美成人基地 | 在线视频麻豆 | 综合色播| aaa毛片视频 | 精品国产乱码一区二区三区在线 | 欧美日韩亚洲第一页 | 97精品国产97久久久久久粉红 | 国产成人久久av免费高清密臂 | 久久艹综合 | 久久午夜羞羞影院 | 在线观看视频中文字幕 | 亚洲国产精品第一区二区 | 中文字幕精品在线 | 色爽网站| 精品国产乱码久久久久久浪潮 | 丝袜美腿亚洲综合 | 99精品在线 | 久久精品国产第一区二区三区 | 我要看黄色一级片 | 欧美日韩精品综合 | 中文在线天堂资源 | 亚洲电影在线看 | 国产韩国日本高清视频 | 亚洲国产99 | 亚洲成av人片在线观看 | 午夜久久 | 97超碰在| 色99视频 | 最近中文字幕高清字幕在线视频 | 日韩a欧美 | 黄色中文字幕在线 | 四虎影视精品永久在线观看 | 中日韩免费视频 | 久久99中文字幕 | 久久久久女人精品毛片 | 久久美女高清视频 | 国产美女视频一区 | 69精品视频 | 国产 在线 日韩 | 激情五月激情综合网 | 99精品欧美一区二区蜜桃免费 | 日本精品视频网站 | 99视频久| 亚洲国产精品一区二区久久,亚洲午夜 | 欧美成人aa | 国产在线精品一区二区不卡了 | 在线国产能看的 | 色综合中文综合网 | 国产精品一区二区av日韩在线 | 精品成人网 | 久久综合九色综合久久久精品综合 | 精品久久久久久久久久久久久久久久 | 97在线免费观看视频 | 亚洲专区欧美专区 | 国产精品成人免费 | 日本在线观看一区 | 97超碰超碰久久福利超碰 | 一区二区伦理 | 在线免费色 | 日韩av偷拍 | 在线观看 亚洲 | 麻豆视频观看 | 久久人人爽人人人人片 | 99精品在线播放 | 久久精品毛片 | 久久久国产精品一区二区中文 | 久久伊人精品天天 | 日韩欧美国产成人 | 久久亚洲欧美日韩精品专区 | 久草剧场 | 中文字幕 影院 | 国产免费资源 | 超碰在线最新网址 | 天天操导航 | 成人免费毛片aaaaaa片 | 日韩电影在线观看一区二区 | 2024国产精品视频 | 9在线观看免费高清完整版 玖玖爱免费视频 | 亚洲成人精品在线观看 | 中文字幕av在线播放 | 国产免费久久 | 久久电影网站中文字幕 | 日本精品中文字幕在线观看 | 免费看的黄色录像 | 超碰人人做 | 在线综合 亚洲 欧美在线视频 | 天天天天射 | 天天操天天操天天操天天操天天操 | 国产一级在线免费观看 | 久久免费99精品久久久久久 | 久久8精品| 中文字幕精 | 精品国产一区二区三区蜜臀 | 白丝av免费观看 | wwwwww黄| 日韩免费电影一区二区三区 | 日韩精品视频在线观看免费 | 婷婷色综合 | 国产日韩三级 | 亚洲国产精品小视频 | 在线观看一区二区视频 | 狠狠干网址| 一区二区在线电影 | 国产一级二级视频 | 日日干天天 | 欧美电影黄色 | 久久久久9999亚洲精品 | 免费a v在线 | 国产一区精品在线观看 | 欧美老女人xx | 亚洲国产精品推荐 | 亚洲.www| 日韩欧三级 | 黄色性av | 999热线在线观看 | 国产精品成人在线观看 | 欧美福利视频一区 | 久久不射电影网 | 欧美性生活免费 | 日韩欧美在线视频一区二区 | 久久99精品国产麻豆婷婷 | 亚洲欧洲一级 | 四虎国产永久在线精品 | 五月天综合网站 | 91精品一区二区三区久久久久久 | 国产精品久久久久久久久久久久午夜 | 免费黄色av. | 国产精品永久免费视频 | 狠狠地日 | 久久一区二区三区国产精品 | 亚洲精品国产综合久久 | 欧美色精品天天在线观看视频 | 福利一区视频 | 国产视频999| 国产视频九色蝌蚪 | 日黄网站 | 国产精品va最新国产精品视频 | 五月天激情综合 | 九九99 | 婷婷网址| av在线免费播放 | 国产 欧美 日产久久 | 国产成人av免费在线观看 | 中文字幕在线观看第二页 | 日韩极品在线 | 久久精品亚洲精品国产欧美 | 尤物97国产精品久久精品国产 | 日韩一区在线免费观看 | 国产精品普通话 | 中文字幕不卡在线88 | 美女视频免费精品 | 婷婷六月中文字幕 | 人人超碰免费 | 99视频在线免费 | 亚洲欧美日本一区二区三区 | 91麻豆精品久久久久久 | 91香蕉视频好色先生 | 国内精品免费 | 91精品久久香蕉国产线看观看 | 干狠狠 | 国产精品密入口果冻 | 国产三级精品在线 | 亚洲欧美视频网站 | 久久国产精品视频免费看 | 午夜三级影院 | 91精品国产福利在线观看 | 久久久久影视 | 又黄又爽的视频在线观看网站 | 人人爱爱人人 | 国产一区在线免费观看视频 | 福利一区二区三区四区 | 国产91影视 | 国产一区二区在线免费播放 | 91精品推荐 | 综合激情久久 | 久久成人午夜视频 | 欧美久久久影院 | 香蕉日日 | 国产亚洲精品美女 | 999久久久国产精品 高清av免费观看 | 九九热在线免费观看 | 欧美性粗大hdvideo | av丝袜天堂 | 国产艹b视频 | 六月丁香综合 | 国产二区精品 | 亚洲国产理论片 | 久久久一本精品99久久精品66 | 国产精品毛片一区二区在线 | 久久久午夜精品理论片中文字幕 | 亚洲成a人片77777潘金莲 | 国产中文字幕视频 | 黄网站色视频 | 一区二区三区动漫 | 国产五月色婷婷六月丁香视频 | 黄www在线观看 | 国产视频亚洲精品 | 久久精品99国产国产精 | 精品女同一区二区三区在线观看 | 天天干,天天射,天天操,天天摸 | 久久精品观看 | 免费av网址在线观看 | 国偷自产中文字幕亚洲手机在线 | 精品一区在线 | 午夜婷婷综合 | 久久免费黄色网址 | 亚洲欧美国产日韩在线观看 | 久久婷婷综合激情 | 免费黄在线观看 | 亚洲成人av影片 | 国产精品日韩欧美一区二区 | 欧美视频日韩视频 | 国产成人精品一区二区三区网站观看 | 大荫蒂欧美视频另类xxxx | 亚洲国产mv | 亚洲乱码在线 | 五月婷婷综合在线观看 | 久久女教师 | 狠狠干天天操 | 蜜臀av网址| 69国产盗摄一区二区三区五区 | 成人国产精品免费 | 91日韩精品视频 | 国产精品久久久久久久久久免费看 | 国产偷国产偷亚洲清高 | 久久成人精品电影 | 免费看国产a | 国产精品a成v人在线播放 | 99热国产在线 | 国产日本三级 | 精品国内自产拍在线观看视频 | 国产精品一区二区美女视频免费看 | 国产一级在线观看 | 爱色av.com| 日韩天天操 | 国产一级片一区二区三区 | 五月婷综合网 | 毛片在线播放网址 | 91网站在线视频 | 久久国产精品久久国产精品 | 欧美a级在线免费观看 | 综合婷婷久久 | 亚洲精品国偷拍自产在线观看 | 天天天天天天天天操 | 97成人免费视频 | 在线观看v片 | 97av超碰| 九九日九九操 | 91色网址 | 亚洲欧美日韩一区二区三区在线观看 | 天天干人人插 | 少妇视频一区 | 中文在线中文资源 | 日韩高清精品免费观看 | 国产在线999 | 美女精品久久久 | 又黄又刺激的网站 | 中文字幕av网站 | 月丁香婷婷| 国产91精品看黄网站在线观看动漫 | 日韩理论| 久久久久久久久亚洲精品 | 日本一区二区三区免费看 | 最新精品视频在线 | 九九精品视频在线看 | 毛片视频电影 | av中文天堂在线 | 一级性生活片 | 免费能看的av | 91 在线视频播放 | 999久久| 亚洲日本黄色 | 中文字幕在线观看播放 | 免费在线观看av网址 | 国产精品久久久久久久久费观看 | 国产剧情久久 | 狠狠干成人 | 狠狠的操你 | 日韩av高潮 | 精品久久综合 | 国内丰满少妇猛烈精品播放 | 亚洲精品美女在线 | 91丨九色丨高潮 | 国产精品午夜免费福利视频 | 国产美女网站在线观看 | 精品国产乱码久久久久久天美 | 久久这里有 | 成人午夜影院 | 日韩精品短视频 | 男女啪啪免费网站 | 四虎在线免费观看 | 日韩高清免费在线观看 | www中文在线 | 99精品国产成人一区二区 | 久久久久久久久久久免费视频 | 久久久在线视频 | 精精国产xxxx视频在线播放 | 免费特级黄毛片 | 丝袜网站在线观看 | 久草影视在线观看 | 波多野结衣最新 | 欧美日韩在线播放 | 超碰成人免费电影 | 国产区在线 | 久久久免费看视频 | 99久久国产免费,99久久国产免费大片 | 一级α片免费看 | 久久精品这里热有精品 | 91九色在线播放 | 91香蕉视频好色先生 | 久久日韩精品 | 免费看污片 | 亚洲精品一区二区精华 | 欧美日韩一区二区在线 | 精品1区二区 | 亚洲欧美激情精品一区二区 | 91视频这里只有精品 | 欧美日韩久久不卡 | 亚洲精品午夜国产va久久成人 | 日韩一区二区三区免费视频 | 亚洲伦理中文字幕 | 欧美精品一区二区在线播放 | 国内精品久久久久久久久久久 | 国产精品av一区二区 | av在线进入 | 四虎在线观看网址 | 亚洲国产中文字幕在线观看 | 久久视频在线观看中文字幕 | 夜夜操综合网 | 日韩欧美精品在线 | 在线视频日韩欧美 | 免费在线观看成人小视频 | 久久久久国产一区二区三区四区 | 性色av香蕉一区二区 | 日韩欧美在线一区 | 中文字幕在线观看免费 | 久久av在线 | 久久国产午夜精品理论片最新版本 | 久久久久成 | 97看片网| 有码一区二区三区 | 日韩激情久久 | 97超碰在线资源 | 久久精品系列 | 国产91精品久久久久久 | 久草资源在线 | 国产日女人| 91高清免费 | 日韩av午夜在线观看 | 国产精品a成v人在线播放 | 69视频在线播放 | 日本99久久 | 亚洲成人欧美 | 天天干夜夜操视频 | 国产精品一区专区欧美日韩 | 国产九九九九九 | 欧美在线a视频 | 黄色精品一区 | 婷婷亚洲综合 | 超碰免费在线公开 | 久久久久欠精品国产毛片国产毛生 | 成人免费 在线播放 | 久久99国产精品 | 999抗病毒口服液 | 国产福利免费在线观看 | 久久dvd| 麻豆一区在线观看 | 天天色天天综合 | 国产一级一片免费播放放 | 亚洲国产精品成人精品 | 欧美激情视频免费看 | 欧美大香线蕉线伊人久久 | 久草免费在线视频观看 | 欧美成人在线网站 | 在线观看蜜桃视频 | 色婷婷88av视频一二三区 | 麻豆视频在线播放 | 久久电影国产免费久久电影 | a v在线观看 | 伊人婷婷色 | 99久久久久成人国产免费 | 午夜精品久久久久久久久久 | 国产精品一区二区久久久久 | 97福利视频| 91视频在线播放视频 | 亚洲精品视频在线观看视频 | 香蕉影视在线观看 | 国产免费一区二区三区最新 | 天天操天天射天天插 | 国产亚洲欧美在线视频 | 碰超在线观看 | 日本黄色a级大片 | 一区二区视频在线观看免费 | 婷婷免费视频 | 在线观看免费视频你懂的 | 91探花系列在线播放 | 亚洲综合在线视频 | 中文字幕乱在线伦视频中文字幕乱码在线 | av成人黄色| 日本三级大片 | 国产午夜精品视频 | 亚洲精品福利在线观看 | 国产亚洲综合在线 | 中文字幕一区二区三 | 国产精品久久久免费 | 国产69精品久久久久99尤 | 免费成人在线观看 | 日韩中文字幕在线看 | 成人高清av在线 | 国产精品va在线观看入 | 色婷婷久久一区二区 | 亚洲日本va午夜在线影院 | 日韩久久久久久久久久久久 | 久久免费99 | 伊人资源视频在线 | 欧美亚洲精品一区 | 国产福利精品视频 | 久久爱导航 | 成人黄色影片在线 | 亚洲日本va午夜在线影院 | 精品国产_亚洲人成在线 | 欧美一级免费在线 | 成年人免费观看在线视频 | 91精品国产综合久久福利不卡 | 91探花系列在线播放 | 欧美精品久久天天躁 | 在线观看黄网 | 中文伊人| 日韩av电影一区 | 国产午夜免费视频 | 制服丝袜一区二区 | 色黄久久久久久 | 亚洲伦理电影在线 | 九九热久久免费视频 | 99国产精品一区 | 婷婷伊人五月 | 91豆麻精品91久久久久久 | 欧美韩国日本在线观看 | 精品特级毛片 | 91网站观看| 久99久视频| 91久久久久久久 | 国产免费影院 | 中文资源在线官网 | 久久五月情影视 | 精品亚洲视频在线 | 久久久不卡影院 | 激情黄色一级片 | 狠狠五月婷婷 | 夜夜躁狠狠躁日日躁视频黑人 | 精品你懂的 | 日韩高清激情 | 久久综合欧美精品亚洲一区 | 91传媒激情理伦片 | 亚洲午夜精品电影 | 欧美久久久一区二区三区 | 又黄又刺激视频 | 国产精品地址 | 久久精品网站视频 | 97日日碰人人模人人澡分享吧 | 天天干,夜夜爽 | 久久国产亚洲 | 99精品福利视频 | 久久99精品久久只有精品 | 久草在线视频在线观看 | 久久久精华网 | 成人午夜电影网站 | 在线va网站 | 国产一区播放 | 欧美在线视频一区二区三区 | av在线之家电影网站 | 丝袜+亚洲+另类+欧美+变态 | 午夜精品久久久99热福利 | 日本成人中文字幕在线观看 | 成人污视频在线观看 | 欧美成年人在线观看 |