搶先一步
VMware 提供訓練和認證,以加速您的進展。
了解更多在這篇部落格文章中,我將向您展示如何使用 Spring Integration 和 dm Server 建立鬆散耦合且可擴展的應用程式。使用 OSGi 的額外好處是,我們可以在執行時變更應用程式的行為,當然我們也會從中獲得一些樂趣。首先,我將快速重點說明設計並行應用程式的原因,然後我將描述整合 OSGi 捆綁包與訊息傳遞的不同策略。在此過程中,您將瞥見我們的工具和 dm Server 的一些功能。如果您已下載並安裝最新的 SpringSource Tool Suite 和 dm Server,您應該能夠自己完成此操作。您不需要範例程式碼即可理解本文,但如果您有興趣,範例程式碼將在 Spring Integration sandbox 中提供。
同步崩潰
應用程式中的同步呼叫執行良好,但它們無法擴展。這之前已經被記錄了很多次,所以我會快速複習一下,然後繼續。當您進行同步呼叫時,呼叫執行緒必須阻塞,直到呼叫完成。如果您碰巧在該方法中執行 I/O,則阻塞執行緒會浪費 CPU 週期。如果您有一個大規模並行的 Web 應用程式,這不是太大的問題,因為您可以增加您正在使用的執行緒池的最大大小。但是,如果您需要從單一呼叫中充分利用伺服器的 CPU 效能,那麼您就倒楣了。由於一個執行緒在一個核心上執行,您擁有的核心越多,單執行緒程式的效率就越低。
訊息傳遞來救援
親自投入並行程式設計非常有趣,但這並不是最容易的事情,您可能希望今天早點完成工作。這就是 Spring Integration 可以幫助您的地方。它為您提供所需的並行處理的所有控制權,而無需您負責並行程式設計的低階細節。
OSGi 如何提供幫助?
您可以完全避免同步崩潰,而無需 OSGi。它只是讓生活變得更好,您不應該錯過它。每次進行一點變更就完全重新部署和重新啟動 jvm 並不好玩。還有另一件事使 OSGi 和訊息傳遞的組合非常有趣。如果企業應用程式變得龐大,您必須在某個時候模組化。在同一個傳統伺服器中執行多個模組是災難的根源(也稱為 jar 地獄)。因此,在傳統架構中,人們在許多情況下過早地擴展規模。這造成了一個非常糟糕的設置。不同的節點必須透過網路相互交談,並且它們無法共用 CPU 和記憶體等資源。這使得架構效率低下,並嚴重影響效能。您不僅在一個伺服器中的某些核心上浪費週期,而且現在您還在多個節點上重複相同的低效率。更糟糕的是,網路延遲增加了 I/O 等待,而正常的本機方法呼叫就已足夠。
使用 OSGi,您不必承受這種衝擊,您可以在同一個 jvm 中執行不同的捆綁包,因此它們之間的呼叫速度與正常的本機方法呼叫一樣快,而不會出現與在同一個類別路徑上部署不同團隊的 jar 檔案相關的可怕 jar 地獄。擁有一個您可以在執行時變更其行為、與多個團隊合作的應用程式,並且可以幫助您將所需的硬體減少到一台強大的伺服器。聽起來不錯,所以我們開始吧。
如果您希望透過實際的程式碼範例來追蹤部落格,或自行並行編寫範例,則需要具備適當的工具(和程式碼)。要遵循部落格的想法,您不需要執行此操作。我將在此處包含必要的程式碼範例。本文並非旨在成為詳細的操作指南,因此如果您想繼續學習,您必須自行編碼,或者只是使用範例。若要執行此操作,請依照下列步驟操作。
在本節中,我們將使用單一捆綁包,該捆綁包依賴 Spring Integration 並將我們的工作交接給它。此捆綁包將隱藏所有訊息傳遞詳細資訊,如果您只有一小部分系統執行密集工作,這可能正是您所需要的。
我將展示的範例應用程式是為中世紀城鎮開發的。在這些城鎮中,過去有一位城鎮公告員會在街上行走,大聲宣佈當地新聞和公告。有關城鎮(希望保持匿名)已被城鎮公告員工會強迫改善其城鎮公告員勞動力的工作條件,並且由於預算限制,他們希望同時減少員工人數。
他們得出的結論是,實現這些目標的唯一方法是用自動化系統取代城鎮公告員的大部分體力勞動。城鎮公告員只需在他的辦公室舒適地將他的訊息傳遞給這個系統,然後該訊息將分發給城鎮的所有市民。市政廳已經追蹤所有市民,因此最容易將此分發邏輯放在城鎮的市政廳中。
[標題 id="attachment_1096" align="alignnone" width="653" caption="範例中各種捆綁包的概觀。"][/caption]
城鎮公告員捆綁包 決定不對城鎮公告員進行再培訓以使用新系統,因此他仍然會調用城鎮的 cry() 方法,他只是不需要再到處走動並多次執行以覆蓋城鎮的每個部分。公告的分發將由城鎮中的新系統透明地完成。towncrier 捆綁包只有一個類別 TownCrier.java,它被注入它應該公告的 Town。
@Component
public class TownCrier {
private static final Log logger = LogFactory.getLog(TownCrier.class);
@Autowired //Spring will take care of the wiring as usual
private Town town;
private ScheduledThreadPoolExecutor schedule;
@PostConstruct
public void start() {
logger.info("Starting feeder");
schedule = new ScheduledThreadPoolExecutor(1);
TimerTask task = new TimerTask() {
public void run() {
logger.info("Crying the time");
town.cry("Oyez! Oyez! Oyez! It is now " + new Date());
}
};
schedule.scheduleAtFixedRate(task, 1, 1, TimeUnit.SECONDS);
}
}
如果您了解 Spring Integration,您會對此程式碼感到畏縮,並希望改為使用輸入通道配接器和輪詢器,但我們只是在這裡模擬舊版程式碼,請耐心等待。
為了幫助 Spring 引用城鎮(將放置在另一個捆綁包中),我們將使用 Spring DM。如果您以前從未與 OSGi 和 Spring DM 合作過,現在是閱讀 入門指南 的好時機。我們只需在 osgi-context.xml 中新增一個 OSGi 參考元素。
<osgi:reference id="collectorService"
interface="com.springsource.samples.integration.osgi.town.input.Town" />
最後,在 MANIFEST.mf 中,有一個對從中匯出服務的 town 捆綁包的依賴項。
Import-Package: com.springsource.samples.integration.osgi.town.input,
org.apache.commons.logging;version="[1.1.1,1.1.1]",
javax.annotation
同樣,完整程式碼位於 Spring Integration sandbox
Town 捆綁包 城鎮(捆綁包)已完全採用訊息傳遞。他們正在使用 Spring Integration 來處理他們的訊息傳遞和並行性。他們還定義了城鎮公告員和市民(稍後提及)所需的輸入和輸出介面。
Town 介面有一個 cry 方法,我們希望向城鎮公告員公開它的實作。我們可以讓 Spring Integration 為我們建立一個實作,該實作採用字串引數並將其放在訊息中包裝的通道上。這是使用閘道完成的。
<gateway id="inputGateway" default-request-channel="announcements"
service-interface="com.springsource.samples.integration.osgi.town.input.Town" />
<publish-subscribe-channel id="announcements" />
public interface Town {
void cry(String string);
}
由於 Town 介面只有一個方法,我們不需要告訴 Spring Integration 要調用哪個方法,因此此處的 @Gateway 是可選的。
在執行時監聽
城鎮中的市民將在市政廳登記,但不了解訊息傳遞。市民可以使用其 onCry(String string) 方法監聽公告,但不依賴 Spring Integration。在某些情況下,您可能希望執行沒有 Spring Integration 依賴項的捆綁包,但在使用 Spring Integration 的事件驅動架構中啟用它。
範例在 CityHall 上的 Town 捆綁包中使用服務啟動器,該啟動器負責解包訊息並將其推送給市民
@ServiceActivator
public void onCry(String announcement) {
for (Citizen consumer : citizens) {
consumer.onCry(announcement);
}
}
為了允許市民自行註冊,CitizenRegistry 作為 OSGi 服務公開。
<osgi:service id="citizenRegistry" ref="cityHall"
interface="com.springsource.samples.integration.osgi.town.output.CitizenRegistry" />
市民註冊表服務也由 CityHall 實作,以維護公告分發到的市民集合。
在 scribe 捆綁包中,實作了 Citizen 的範例。它透過 OSGi 參考引用 CitizenRegistry。
<osgi:reference id="citizenRegistry"
interface="com.springsource.samples.integration.osgi.town.output.CitizenRegistry" />
Scribe 在初始化期間將自己註冊到市民註冊表,並隨後記錄它收到的所有公告。
這樣,只有 town 捆綁包的程式碼需要變更才能開始使用新系統,而 citizen 捆綁包可以保持不變。當然,可能有充分的理由擁有了解正在進行的訊息傳遞並直接共用通道的多個捆綁包。在下一節中,我們將研究這一點。
假設城鎮也與中央政府打交道。政府以政府捆綁包的形式向城鎮派遣代表。這位代表直接了解公告通道,因此無需使用閘道或服務啟動器將其與之隔離。城鎮將 announcementsChannel 作為 OSGi 服務公開
<osgi:service id="announcementsChannel" ref="announcements"
interface="org.springframework.integration.channel.SubscribableChannel" />
為了將政府法令傳送到城鎮的公告通道,我們在範例中的政府捆綁包中設定了一個閘道,但這可以是任何端點。重點是從政府捆綁包中引用城鎮捆綁包中的通道
<osgi:reference id="announcementsChannel"
interface="org.springframework.integration.channel.SubscribableChannel" />
現在您可以在另一個捆綁包中將其用作普通通道
<si:service-activator input-channel="announcementsChannel"
ref="nationalArchive" />
<si:gateway
service-interface="com.springsource.samples.integration.osgi.government.GovernmentDecreeGateway"
id="decreeer" default-request-channel="announcementsChannel" />
為了簡單起見,範例實作了非常簡單的本機端點,但是一旦通道橋接捆綁包,就沒有什麼可以阻止您使用 Spring Integrations 配接器走出 jvm。
假設政府捆綁包成為銀行的內部貸款/信貸部門(其對他人的貸款利率可能會根據聯準會利率而變化 - 可以建立在不同的架構上)。我不是金融專家,也不是您所在領域的專家,因此我不會自作主張地告訴您此技術解決方案的具體應用方式。未來,我們將將範例重構為更實際的領域,並將其新增到範例中,為您提供一些想法。如果您有特殊要求,請務必在此處評論。
要設計可擴展的應用程式,您需要考慮同步交接的問題。訊息傳遞可以解決許多這些問題。為了發展最好在單一 jvm 上執行的最佳效能大型應用程式,OSGi 是一種引人注目的替代方案。將兩者與 Spring Integration 和 dm Server 結合使用既強大又簡單。在本文中,您已經了解如何