使用OSGi構(gòu)建面向服務(wù)的聯(lián)絡(luò)管理應(yīng)用程序
譯文【51CTO精選譯文】本文是《你好,OSGi》系列的第八部分。在之前一篇已經(jīng)使用Spring DM創(chuàng)建了Hello World應(yīng)用,下面的步驟就是要進(jìn)行服務(wù)套件的導(dǎo)入和導(dǎo)出了。簡(jiǎn)單來(lái)說(shuō)就是,構(gòu)建一個(gè)面向服務(wù)的聯(lián)絡(luò)管理應(yīng)用程序。
51CTO編輯推薦:OSGi入門與實(shí)踐全攻略
導(dǎo)入和導(dǎo)出服務(wù)套件
聯(lián)絡(luò)管理(Contact Management)應(yīng)用程序包含兩個(gè)套件。第一個(gè)套件是 ContactDAO,與數(shù)據(jù)庫(kù)進(jìn)行會(huì)話并將 ContactDAO 對(duì)象導(dǎo)出為OSGi服務(wù)。第二個(gè)套件是之前開(kāi)發(fā)的 HelloWorld 應(yīng)用程序,我們將其擴(kuò)展,導(dǎo)入 ContactDAO 對(duì)象(即被導(dǎo)出的OSGi服務(wù))。
下面讓我們先從創(chuàng)建 ContactDAO 套件開(kāi)始。為了簡(jiǎn)單易行,我們不會(huì)在套件中添加真實(shí)的數(shù)據(jù)庫(kù)互動(dòng)邏輯;作為替代,每個(gè)方法僅將其方法名稱寫到 Eclipse 控制臺(tái)。
首先創(chuàng)建 com.javaworld.sample.osgi.spring.contact.Contact.java 類,用來(lái)從 ontactDAO 將數(shù)據(jù)傳遞到 HelloWorld 套件。程序如代碼清單 3 所示。(Contact.java 是一個(gè)簡(jiǎn)單的類,表示數(shù)據(jù)庫(kù)中的一個(gè)聯(lián)絡(luò)記錄。)
代碼清單 3. Contact.java
- package com.javaworld.sample.osgi.spring.contact;
- public class Contact {
- int contactId;
- String firstName;
- String lastName;
- public int getContactId() {
- return contactId;
- }
- public void setContactId(int contactId) {
- this.contactId = contactId;
- }
- }
下一步,我們來(lái)創(chuàng)建 ContactDAO.java 接口,程序如代碼清單 4 所示。
代碼清單 4. ContactDAO 接口
- package com.javaworld.sample.osgi.spring.contact;
- public interface ContactDAO {
- public List getContactList();
- public Contact getContact(int contactId);
- public void insertContact(Contact contact);
- public void updateContact(Contact contact);
- public void deleteContact(int contactId);
- }
ContactDAO 是一個(gè)簡(jiǎn)單的 CRUD 接口:它定義了創(chuàng)建、更新、檢索以及刪除操作的方法。
現(xiàn)在,創(chuàng)建 ContactDAO.java 類的實(shí)現(xiàn),程序如代碼清單 5 所示。
代碼清單 5. ContactDAOImpl.java
- package com.javaworld.sample.osgi.spring.contact.impl;
- public class ContactDAOImpl implements ContactDAO {
- public Contact getContact(int contactId) {
- System.out.println("Inside ContactDAOImpl.getContact()");
- return null;
- }
- // Do nothing implementation of all other methods defined in ContactDAO
- }
ContactDAOImpl.java 為 ContactDAO 接口提供了一個(gè)“do nothing”(返回空)的實(shí)現(xiàn)。我們所要做的是利用這個(gè)類將方法名稱寫入到 System.Out。
請(qǐng)注意 Contact 和 ContactDAO 都必須是公共類(為了使用 ContactDAO 服務(wù),其他套件需要訪問(wèn)它們),并且位于 com.javaworld.sample.osgi.spring.contact 包之中。但是,實(shí)際的實(shí)現(xiàn)類 ContactDAOImpl.java(對(duì)于 ContactDAO 套件是一個(gè)內(nèi)部類)位于 com.javaworld.sample.osgi.spring.contact.impl 包中。
下面,我們來(lái)修改 ContactDAO 套件的 MANIFEST.MF 文件,以導(dǎo)出 com.javaworld.sample.osgi.spring.contact 套件,這樣就可以從 HelloWorld 套件訪問(wèn)它了。我們只需在 MANIFEST.MF 中添加一行代碼:Export-Package: com.javaworld.sample.osgi.spring.contact
Spring DM的 Spring 配置
下面,我們將創(chuàng)建 Spring 配置文件。Spring DM中推薦的方法是將配置劃分為兩個(gè)文件,一個(gè)用于定義 Spring bean,另一個(gè)用于將 Spring 輸出為 OSGi 服務(wù)。下面,我們也會(huì)將作為示例的應(yīng)用程序的配置劃分為兩個(gè)文件。第一步是在 META-INF/spring 文件夾中創(chuàng)建一個(gè) contactdao-service.xml 文件,程序如代碼清單 6 所示。
代碼清單 6. Spring 語(yǔ)境(contex)文件
- < ?xml version="1.0" encoding="UTF-8"?>
- < beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
- < bean name="contactDAOService"
- class="com.javaworld.sample.osgi.spring.contact.impl.ContactDAOImpl">
- < /bean>
- < /beans>
這個(gè)簡(jiǎn)單的 Spring 語(yǔ)境文件定義了 contactDAOService,指向 com.javaworld.sample.osgi.spring.contact.impl.ContactDAOImpl 類。
下一步,我們將創(chuàng)建 META-INF/spring/contactdao-osgi.xml 文件,用于將 contactDAOService 對(duì)象導(dǎo)出為 OSGi 對(duì)象:
代碼清單 7. contactdao-osgi.xml
- < ?xml version="1.0" encoding="UTF-8"?>
- < beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:osgi="http://www.springframework.org/schema/osgi"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">
- < osgi:service id="contactDAOOSGiService" ref="contactDAOService"
- interface="com.javaworld.sample.osgi.spring.contact.ContactDAO">
- < /osgi:service>
- < /beans>
contactdao-osgi.xml 僅包含一個(gè) < service> 元素,用于將 Spring bean 導(dǎo)出為公共寄存器里的 OSGi 服務(wù)。服務(wù) < service>[元素]必須最少具有兩個(gè)屬性:一個(gè)是 id 屬性,包含一個(gè)與導(dǎo)出 Spring bean 的名稱相等的值,另一個(gè)是 interface 屬性,它的值應(yīng)與該接口名稱相等(該接口名稱下的服務(wù)將會(huì)被導(dǎo)出)。(< service>元素所支持屬性的完整列表,請(qǐng)參閱 Spring DM參考指南)。
現(xiàn)在我們的 ContactDAO 已經(jīng)準(zhǔn)備好了。下一步是對(duì) HelloWorld 進(jìn)行擴(kuò)展,這樣它就可以使用新的服務(wù)了。
作為消費(fèi)者的 HelloWorld
如果想要這個(gè)簡(jiǎn)單的 HelloWorld 應(yīng)用程序能夠擔(dān)任消費(fèi)者的角色,我們必須賦予它這樣做的權(quán)限。第一步是更改該套件的 MANIFEST.MF 文件,添加一個(gè) Import-Package 語(yǔ)句,如下所示:
- Import-Package: com.javaworld.sample.osgi.spring.contact
現(xiàn)在,HelloWorld 套件將能夠訪問(wèn)從 ContactDAO 套件的 com.javaworld.sample.osgi.spring.contact package 導(dǎo)出的類。
下面我們將修改 HelloWorld.java 類,如代碼清單 8 所示。
代碼清單 8. HelloWorld.java 的更改
- public class HelloWorld {
- ContactDAO contactDAO;
- public ContactDAO getContactDAO() {
- return contactDAO;
- }
- public void setContactDAO(ContactDAO contactDAO) {
- this.contactDAO = contactDAO;
- }
- public void start() throws Exception {
- System.out.println("Hello Spring World!! " );
- System.out.println(contactDAO.getContactList() );
- }
- public void stop() throws Exception {
- System.out.println("Goodbye Spring World!!");
- }
- }
在代碼清單8 中,我們首先將 ContactDAO 作為 Java bean 屬性添加進(jìn)來(lái),包含所有相關(guān)的 getter 和 setter 方法。接著,我們修改類的 start() 方法,來(lái)調(diào)用 ContactDAO 服務(wù)的 getContactList() 方法,以及輸出“Hello Spring World!!”消息。
Spring 配置文件
HelloWorld 套件的 Spring 配置文件分為兩個(gè)文件:helloworld.xml 和 helloworld-osgi.xml。我們先從 helloworld-osgi.xml 開(kāi)始,該文件如代碼清單 9 所示。
代碼清單 9. Spring 配置- helloworld-osgi-xml
- < ?xml version="1.0" encoding="UTF-8"?>
- < beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:osgi="http://www.springframework.org/schema/osgi"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">
- < osgi:reference id="contactDAOService" interface="com.javaworld.sample.osgi.spring.contact.ContactDAO"/>
- < /beans>
這個(gè) helloworld-osgi.xml 文件聲明了一個(gè)引用元素,該元素用于索引 OSGi 服務(wù)并將其作為 Spring bean 在 HelloWorld 套件中可用。之前已經(jīng)提到,引用元素包含兩個(gè)屬性:id 和interface。在將 OSGi 服務(wù)添加為應(yīng)用程序中的 Spring bean 時(shí),Spring DM將使用 id 屬性的值。對(duì)于這種情況,我們已經(jīng)指出,Spring DM應(yīng)使該服務(wù)作為 contactDAOService 在 HelloWorld 套件的應(yīng)用程序語(yǔ)境中可用。
第二個(gè)屬性是 interface。Spring DM將使用該屬性的值來(lái)查找與指定接口匹配的服務(wù)。在示例代碼中,我們已說(shuō)過(guò),我們想要一個(gè)實(shí)現(xiàn) com.javaworld.sample.osgi.spring.contact.ContactDAO 接口的服務(wù)。
Spring DM調(diào)用 BundleContext.getServiceReference() 查找實(shí)現(xiàn)了 com.javaworld.sample.osgi.spring.contact.ContactDAO 接口的服務(wù)。如果在 OSGi 框架中,與需要相匹配的服務(wù)多于一個(gè),那么將返回具有最高等級(jí)的那個(gè)服務(wù)。此外,你還可以使用 filter 屬性來(lái)精確地定義你想要的服務(wù)。
下一步,我們將修改 helloworld.xml 文件,使它能夠?qū)?contactDAOService 對(duì)象注入到我們的 hello bean 中,如代碼清單 10 所示。
代碼清單 10. Spring 配置 - helloworld.xml
- < ?xml version="1.0" encoding="UTF-8"?>
- < beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
- < bean name="hello" class="com.javaworld.osgi.spring.HelloWorld"
- init-method="start" destroy-method="stop" >
- < property name="contactDAO" ref="contactDAOService"/>
- < /bean>
- < /beans>
一旦將 ContactDAOService 注入到套件的應(yīng)用程序語(yǔ)境中,你就能夠使用它作為任何你想要的其他 Spring bean。在示例代碼中,我們將該服務(wù)作為一個(gè) HelloWorld bean 的contactDAO 屬性進(jìn)行注入。
HelloWorld 導(dǎo)入服務(wù)
在 Eclipse IDE 中執(zhí)行你的套件,當(dāng)你啟動(dòng) HelloWorld 套件時(shí),在你的控制臺(tái)里應(yīng)顯示“Hello Spring World!! Inside ContactDAOImpl.getContactList()”消息。在后臺(tái),一旦 Spring extender 套件被啟動(dòng),它將看到存在兩個(gè) Spring 提供的套件。作為響應(yīng),它將首先為 ContactDAO 套件創(chuàng)建一個(gè)應(yīng)用程序語(yǔ)境。同時(shí),它查找 contactdao-osgi.xml 文件并將 ContactDAO 作為公共寄存器中的 OSGi 服務(wù)進(jìn)行導(dǎo)出。接著,它將試圖為 HelloWorld 套件創(chuàng)建一個(gè)應(yīng)用程序語(yǔ)境。看到它具有一個(gè)引用元素,extender 調(diào)用 BundleContext.getService("com.javaworld.sample.osgi.spring.contact.ContactDAO") 方法,目的在于查找實(shí)現(xiàn) com.javaworld.sample.osgi.spring.contact.ContactDAO 接口的類服務(wù)。
在示例代碼(見(jiàn)代碼清單 5)中,ContactDAOImpl 是唯一實(shí)現(xiàn)了該接口的服務(wù),因此 extender 將返回 ContactDAOImpl 的一個(gè)對(duì)象。一旦該對(duì)象被返回,Spring DM就會(huì)將其作為 contactDAO 屬性 注入到 HelloWorld bean 中。
【編輯推薦】