可移植性、炸魚薯條

工程 | Rod Johnson | 2008 年 5 月 9 日 | ...

在 JavaOne 會議期間,在線上和線下,關於 SpringSource Application Platform 的討論非常多。WebSphere 事務架構師 Ian Robinson 的一個最有見地的 評論 之一是:

這一切會影響 WebSphere 嗎?嗯,Spring 核心框架本身沒有任何變化。無論 SpringSource Application Platform 的未來如何,Spring 核心框架專案仍然可以與 WebSphere 互補。就像炸魚薯條一樣。
Ian 的說法完全正確。SpringSource Application Platform 是 Spring 部署的另一種選擇。在……方面沒有任何改變。

SpringSource Application Platform Manifest 頭部

工程 | Glyn Normington | 2008 年 5 月 8 日 | ...

SpringSource Application Platform 由 OSGi 捆綁包構建而成,並支援同樣由 OSGi 捆綁包構建的應用程式。平臺支援 OSGi 的標準功能,但也支援一些額外的清單頭部。許多人曾問:“為什麼 SpringSource 要新增專有頭部?”以及“新頭部有什麼含義?”,因此本文解釋了背景動機以及 Import-LibraryImport-Bundle 的含義。

標準 OSGi 捆綁包支援

平臺基於 OSGi R4.1 標準,或者如果您更喜歡,可以認為是 JSR 291,並使用 Equinox 作為其 OSGi 實現。結果是,您可以使用平臺的工具開發標準的 OSGi 捆綁包,並將這些捆綁包部署到平臺,正如許多使用者自平臺釋出以來一直在做的那樣。

因此,熟悉 OSGi 的開發者可以將平臺用作標準的 OSGi 容器,並受益於平臺的功能,例如:

  • 透過管理控制檯或將捆綁包放入平臺的 pickup 目錄來部署捆綁包的能力;
  • 診斷功能,如解析失敗診斷、應用程式特定跟蹤和自動死鎖檢測;
  • 與 Spring 和 Spring Dynamic Modules 的強大整合,適用於希望使用這些框架的開發人員;以及
  • 從儲存庫自動供應依賴項。
然而,平臺還旨在讓接觸 OSGi 很少或沒有經驗的企業應用程式開發人員能夠輕鬆受益於 OSGi,這給平臺帶來了一些額外的要求。

企業應用程式的其他要求

正如 Sam 最近關於平臺部署選項的 部落格 所解釋的,您可以將現有的單體 WAR 檔案部署到平臺上,而無需瞭解 OSGi - 平臺會為您處理一切。但是,要從共享庫、共享服務以及最終的 PAR 檔案範圍中受益,就需要將單體 WAR 檔案分解為 OSGi 捆綁包。這有多難?

好吧,過程中的一些步驟相對容易,特別是如果遵循了良好的軟體工程實踐並且程式碼已被組織成服務、域和基礎設施元件。這些元件可以轉換為捆綁包,它們之間的依賴關係可以使用 META-INF/MANIFEST.MF 中的標準 OSGi Import-Package 和 Export-Package 頭部來表達。

一個更困難的步驟是表達對 Spring 和 Hibernate 等企業框架的依賴。使用標準的 OSGi Import-Package 和 Require-Bundle 頭部來表達這些依賴關係是完全可能的,如果您想建立將在其他 OSGi 容器中執行的 OSGi 捆綁包,那麼您應該這樣做,但這種方法有一些隱藏的成本。

首先,開發人員必須精確地確定構成給定框架的包。僅僅匯入應用程式程式碼使用的包是不夠的,因為許多企業框架在應用程式載入時會在應用程式的位元組碼中注入進一步的依賴關係。開發人員必須透過試錯來發現需要匯入哪些額外的實現包,以確保編織後的應用程式能夠正確執行。

然後是遷移到框架的新版本的工作,其中構成框架的包的精確集已發生更改。編織所需的附加包通常不是由公共契約定義的,因此可能會發生更改。

此外,生成的包匯入未能正確捕獲設計意圖,這使得將來維護或擴充套件應用程式更加困難。

我們真的不想給使用者帶來這些負擔,因此我們建立了一些額外的 SpringSource Application Platform 特定清單頭部,Import-LibraryImport-Bundle,作為表達對企業框架依賴關係的便捷方式。正如您將在下面看到的,這些頭部只是“語法糖”,它們本身就是標準的 OSGi 包匯入。

Import-Library

基本語法與其他清單頭部類似:
    Import-Library: <librarySymbolicName>;version=<versionRange>
其中 <librarySymbolicName> 是庫的“符號名稱”,<versionRange> 是使用 OSGi 版本範圍表示法可接受的庫版本範圍。庫定義指定了庫的符號名稱和版本,這兩個共同唯一地標識了平臺上的庫。

如果您不熟悉 OSGi 版本範圍表示法,最常用的形式是最小版本範圍,例如 2,表示“版本 2 或更高版本”,以及“半開”範圍,例如 [2.2.1,2.2.2),表示 2.2.1(含)和 2.2.2(不含)之間的任何版本。如果省略 version=<versionRange>,並省略分號分隔符,則預設範圍包含所有版本。

對於每個庫匯入,平臺會選擇具有給定符號名稱和給定版本範圍內的最高版本庫。然後,平臺會將庫匯入替換為一組包匯入,這些包匯入匹配該庫捆綁包匯出的所有包。平臺會檢測到捆綁包匯入兩個或多個匯出公共包的庫的情況,會發出適當的日誌訊息,並阻止匯入捆綁包的安裝。

因此,例如,以下頭部匯入了介於 2.5.4(含)和 2.5.5(不含)之間的某個版本的 Spring Framework 庫

    Import-Library: org.springframework.spring;version="[2.5.4,2.5.5)"

可選庫匯入

您可以使用以下語法指示庫匯入是可選的。請注意,特殊分隔符 := 表示一個“指令”,它會修改清單頭部的語義,而分隔符 = 表示一個“匹配屬性”,如 version
    Import-Library: <librarySymbolicName>;version=<versionRange>;resolution:=optional

如果未指定 resolution,或者指定為 mandatory,則包含匯入庫頭部的捆綁包將無法安裝,如果不存在具有給定符號名稱且版本在給定範圍內的庫。但是,如果指定了 resolution:=optional,則在沒有合適的庫可用時,將忽略該庫匯入。

因此,例如,以下頭部從 2.5 版本開始匯入某個版本的 Spring Framework 庫,但如果不存在合適的庫,則會被忽略。

    Import-Library: org.springframework.spring;version="2.5";resolution:=optional

匯入多個庫

如果您需要匯入多個庫,請在單個 Import-Library 清單頭部中指定一個逗號分隔的庫匯入列表,如下例所示:
    Import-Library: org.foo.p;version="[1,2)",org.bar.q;version="[2,3)"

Import-Bundle

Import-Bundle 是一個額外的便利功能,適用於庫僅由一個捆綁包組成且建立庫定義不便的情況。語法非常類似於 Import-Library,只是它引用的是捆綁包的符號名稱和版本,而不是庫的。

正如您所期望的,對於每個匯入的捆綁包,平臺會選擇具有給定符號名稱和給定版本範圍內的最高版本捆綁包。然後,平臺會將捆綁包匯入替換為一組包匯入,這些包匯入匹配該捆綁包匯出的包。

因此,例如,以下頭部匯入了 Hibernate 物件關係對映 捆綁包。

    Import-Bundle: com.springsource.org.hibernate;version="[3.2.6,3.2.7)"

為什麼不過載 Require-Bundle

如果您熟悉 OSGi,您可能會問自己,為什麼我們不過載 Require-Bundle 而引入 Import-Bundle

嗯,我們希望 Require-Bundle 保留其標準語義,包括將拆分的包組合在一起的能力。但我們希望 Import-LibraryImport-Bundle 具有與 Import-Package 相同的底層語義,從而避免拆分包的複雜性。

我們還預計,隨著平臺隨時間的推移而發展,我們將需要向 Import-LibraryImport-Bundle 新增進一步的指令,這些指令不適合新增到 Require-Bundle

下一步是什麼?

平臺 beta 計劃 正在進行中,我們將聽取所有關於平臺功能(包括新的清單頭部)的反饋。

對於希望利用 Platform 的頭資訊,但又需要生成可在其他 OSGi 容器上執行的 bundle 的使用者,我們計劃推出一個工具,該工具將替換 `Import-Library` 和 `Import-Bundle`……

SpringSource 應用平臺部署選項

工程 | Sam Brannen | 2008 年 5 月 6 日 | ...

自上週三釋出 SpringSource 應用平臺以來,眾多開發人員下載了 1.0.0 測試版並開始試用該平臺。結果,人們開始詢問:“如何在平臺上部署我的應用程式?我有哪些部署和打包選項?”此外,開發人員迫切希望看到可用的示例。作為回應,S2AP 團隊將在未來幾周釋出幾個示例應用程式,演示這些功能以及更多內容,但在您拿到這些示例之前,我想先給您一個高層次的…

在 OSGi 上使用 SpringSource Application Platform 執行 Spring 應用程式

工程 | Rob Harrop | 2008 年 5 月 2 日 | ...

很多人一直在問 SpringSource Application Platform 究竟能為 Spring 應用程式做什麼,使其在 OSGi 上執行良好,這超出了 OSGi 和 Spring Dynamic Modules 開箱即用的功能。Adrian 昨天的帖子重點介紹了一些一般性問題,現在我們來看一些細節。

在 OSGi 上執行 Spring 應用程式面臨的三個最具挑戰性的方面是

  • 載入時編織
  • 類路徑掃描
  • 執行緒上下文類載入器管理

其餘但不太有趣的方面包括:JSP 支援、TLD 掃描、註解匹配和資源查詢。總而言之,有一些相當多的問題需要解決才能使應用程式平穩部署。

載入時編織

載入時編織是支援的一項最棘手的功能。在基本層面上,它需要掛鉤到 Equinox 的 ClassLoader,以便在 defineClass 呼叫期間可以附加和使用標準的 ClassFileTransformers。在此基礎上,許多 LTW 的用法需要訪問一個一次性的 ClassLoader,該 ClassLoader 可用於檢查型別以決定在編織期間需要做什麼,而不會影響實際的 ClassLoader

這個基本級別的支援實際上是相當容易實現的。困難之處在於,當編織由一個 bundle 中的類驅動,但另一個 bundle 中的類需要被編織時。這在企業應用程式中很常見,其中一個 bundle 包含領域實體,另一個 bundle 包含使用 JPA EntityManager 的型別。Platform 透過確保應用程式中的所有 bundle 都可以使用適當的 ClassFileTransformers 進行編織來處理這種複雜性。

當您開始將編織傳播到其他 bundle 時,您確實需要知道何時停止。如果您只是將編織應用於所有 bundle,那麼應用程式將會相互干擾。Platform 透過顯式地限定編織範圍,使其僅應用於應用程式中的模組,從而防止這種情況發生。

LTW 的另一個問題是它會使重新整理複雜化。當一個 bundle 被重新整理時,OSGi 將重新整理所有依賴於它的 bundle。這意味著,在我上面給出的例子中,重新整理領域 bundle 會導致 EntityManager bundle 被重新整理。然而,重新整理 EntityManager **不會**重新整理領域 bundle,這意味著編織可能不同步。Platform 透過將重新整理傳播到受編織影響的其他 bundle 來處理此問題。

類路徑掃描

對於類路徑掃描,主要問題是 Equinox 不暴露標準的 jar:file: 資源。Platform 在中間放置了一個介面卡,以便庫可以看到它們期望的資源協議。這有一個很好的副作用,就是使**大量**第三方庫能夠工作——這不僅僅是類路徑掃描的修復。

執行緒上下文類載入器管理

許多第三方庫使用執行緒上下文 ClassLoader 來訪問應用程式型別和資源。OSGi 中的每個 bundle 都有自己的 ClassLoader,因此,在任何時候只能公開一個 bundle 作為執行緒上下文 ClassLoader。這意味著,如果第三方庫需要檢視分佈在多個 bundle 中的型別,它將無法按預期工作。

Platform 透過建立一個 ClassLoader 來解決這個問題,該 ClassLoader 匯入您應用程式中每個模組的所有匯出的包。然後,此 ClassLoader 作為執行緒上下文 ClassLoader 公開,使第三方庫能夠看到您應用程式中的所有匯出型別。

這只是 Platform 所解決問題的一小部分,但希望它能讓您對 Platform 對 Spring Framework 使用者意味著什麼有所瞭解。

完善全貌:Spring、OSGi 和 SpringSource 應用平臺

工程 | Adrian Colyer | 2008年5月1日 | ...

** 5月2日更新,包含案例研究:- 詳見此帖子底部 ** 我相信閱讀本部落格的大多數人昨天都看到了 SpringSource 應用平臺的釋出公告。如果沒有,請務必檢視 Rob 的部落格文章,其中描述了一些動機、程式設計模型和路線圖。

有一些常見的疑問,我想在這篇文章中直接解決。之後,我將描述另外兩個激動人心的公告,它們補充了 SpringSource 應用平臺本身,但昨天沒有登上頭條:……

介紹SpringSource Application Platform

工程 | Rob Harrop | 2008 年 4 月 30 日 | ...

經過數月緊張的編碼,我很高興地宣佈 SpringSource Application Platform 1.0 的 beta 版本釋出。

2007 年初,我們開始討論替代單體式、重量級應用程式伺服器的可能方案,企業 Java 已與這些伺服器形影不離。客戶正在尋找一個輕量級、模組化且足夠靈活的平臺,以滿足其開發和部署需求。

Spring 和 Tomcat 的組合表明,開發人員和運維人員可以在生產環境中成功使用一個輕量級的平臺。儘管這種組合取得了成功,但缺乏模組化和對非 Web 應用程式的顯式支援限制了其適用性和靈活性。

我們著手構建 SpringSource Application Platform 以滿足這些需求並消除這些限制。

Platform 的核心是 Dynamic Module Kernel (DMK)。DMK 是一個基於 OSGi 的核心,充分利用了 OSGi 平臺的模組化和版本控制功能。DMK 基於 Equinox 並擴充套件了其在配置和庫管理方面的功能,同時為 Platform 提供了核心功能。

SpringSource Application Platform Architecture

為了保持最小的執行時佔用空間,OSGi bundle 由 DMK 配置子系統按需安裝。這使得應用程式可以安裝到執行中的 Platform 中,並且其依賴項可以從外部儲存庫中滿足。這不僅消除了手動安裝所有應用程式依賴項的繁瑣工作,而且最大限度地減少了記憶體使用。

DMK 本身需要一套最小的 bundle 來執行,並透過一個 **profile** 進行配置,以精確控制載入的附加模組集。例如,DMK 不需要 Tomcat,但預設的 Platform profile 包含 Tomcat 以允許部署 Web 應用程式。如果您想在沒有 Tomcat 的情況下執行 Platform,只需編輯 profile 即可,它就不會被安裝。(如果您嘗試這樣做,請記住,刪除 Web 支援意味著 Web 模組將不再部署,因此請刪除 pickup 目錄中的內容,以免 Platform 在啟動時嘗試安裝 Admin 和 splash 螢幕應用程式。)預設的 Platform 配置(安裝了管理控制檯)僅佔用 15MB 記憶體。

我對企業 Java 的一個長期不滿是,應用程式經常被塞進牽強的孤島,並且缺乏對不同應用程式型別的顯式支援。考慮一個線上商店的應用程式。該應用程式有一個 Web 前端、一個訊息驅動的訂單處理模組、一個批處理驅動的庫存重新排序模組和一個 B2B Web 服務模組。如今,許多此類應用程式將被打包成 WAR 或 EAR,並且模組將非常相似,對模組型別差異的支援很少。有趣的是,許多人會將此稱為 Web 應用程式,而不是帶有 Web 模組的應用程式。

在 SpringSource Application Platform 中,應用程式是模組化的,每個模組都有一個 **personality**,用於描述它是什麼型別的模組:Web、批處理、Web 服務等。Platform 以特定於 personality 的方式部署每個 personality 的模組。例如,Web 模組在 Tomcat 中使用 Web 上下文進行配置。應用程式中的每個模組都可以獨立於其他模組進行更新,同時保持作為大型應用程式一部分的身份。無論您構建哪種型別的應用程式,程式設計模型仍然是標準的 Spring 和 Spring DM。

在 1.0 Platform 版本中,我們支援 **web** 和 **bundle** personality,這使您能夠構建複雜的 Web 應用程式。未來的版本將根據後續詳述包含對更多 personality 的支援。

構建應用程式

Platform 支援三種形式的應用程式打包

  1. Java EE WAR
  2. 原始 OSGi bundle
  3. 平臺歸檔 (PAR)

Platform 直接支援標準的 WAR 檔案。在部署時,WAR 檔案將被轉換為 OSGi bundle 並安裝到 Tomcat 中。所有標準的 WAR 合約都得到遵守,您現有的 WAR 檔案應該可以直接部署而無需更改。

任何符合 OSGi 標準的 bundle 都可以直接部署到 Platform 中,並可以充分利用對 `Import-Package` 和 `Require-Bundle` 所引用的任何依賴項進行的即時配置。

PAR 格式是為 Platform 打包和部署應用程式的推薦方法。PAR 只是一個 OSGi bundle(模組)的集合,這些 bundle 被分組到一個標準的 JAR 檔案中,並帶有一個唯一標識應用程式的名稱和版本。PAR 檔案作為單個單元部署到 Platform。Platform 將提取 PAR 中的所有模組並進行安裝。第三方依賴項將根據需要即時安裝。

與直接將 bundle 部署到 Platform 相比,PAR 格式有三個主要優勢。首先,它更簡單。一箇中等規模的企業應用程式可能包含 12 個以上的 bundle - 手動部署這些 bundle 將非常繁瑣。其次,PAR 檔案為應用程式中的所有 bundle 形成了一個顯式的範圍,防止使用重疊型別或服務的應用程式之間發生衝突。此範圍還用於一些高階功能,例如載入時織入,以確保一個應用程式的織入不會干擾另一個應用程式的織入。最後,PAR 形成了一個邏輯分組,用於定義哪些模組是應用程式的一部分以及應用程式有哪些第三方依賴項。此分組由管理工具用於提供應用程式的詳細檢視。典型的 PAR 應用程式如下所示:

PAR File Structure

應用程式中模組之間的依賴關係通常使用 `Import-Package` 和 `Export-Package` 來表示。對第三方庫的依賴關係也可以用同樣的方式表示,但對於許多庫來說,這可能容易出錯且耗時。在使用 Hibernate 等庫時,您通常需要匯入比最初預期的更多的包。為了解決這個問題,您可以*使用* `Require-Bundle`,但這存在一些語義上的粗糙之處,例如分割包,其中一個邏輯包被分割到兩個或多個類載入器中,導致執行時問題。Platform 引入了兩種新的機制來引用第三方依賴項:`Import-Bundle` 和 `Import-Library`。`Import-Bundle` 類似於 `Require-Bundle`,但它避免了分割包和其他與 `Require-Bundle` 相關的問題。`Import-Library` 提供了一種機制,可以在單個宣告中引用一組 bundle 匯出的所有包,例如 Spring Framework 中的所有 bundle。

Bundle-SymbolicName: com.myapp.dao.jdbc
Bundle-Version: 1.0.0
Import-Bundle: org.apache.commons.dbcp;version="1.2.2.osgi"
Import-Library: org.springframework.spring;version="2.5.4.A"

在這裡,我有一個依賴於 Commons DBCP bundle 和 Spring Framework 庫的模組 bundle。Spring Framework 庫包含使用 Spring 在應用程式中所需的所有 bundle。

`Import-Library` 和 `Import-Bundle` 在後臺會展開為 `Import-Package`,因此與標準的 OSGi 語義一致。

Platform 理解模組的 personality,並能從中推斷出如何配置模組的執行環境。在部署 Web 模組時,典型的 Spring MVC 應用程式所需的所有 Servlet 基礎設施都會自動建立,從而無需在應用程式中重新建立這些樣板程式碼。在 1.0 最終釋出版中,將為 Web 模組 personality 新增更多智慧功能,以支援 Spring Web Flow 等其他技術。

無論您選擇哪種打包格式,程式設計模型都只是 Spring Framework 和 Spring Dynamic Modules,其他 Spring Portfolio 產品執行在其之上。

可服務性

可服務性是整個工程團隊的關鍵考慮因素。我們花費了大量時間來研究日誌訊息的格式和堆疊跟蹤的大小,以確保診斷應用程式問題儘可能容易。每當發現一項重複且耗時的任務時,我們都會尋找一種方法來自動化它或完全消除它。

為了幫助診斷問題,Platform 在日誌和跟蹤訊息之間進行了嚴格的劃分。日誌訊息旨在供終端使用者使用,讓您無需篩選大量跟蹤內容即可獲取最重要的失敗資訊。所有應用程式故障都會顯示並編碼在日誌輸出中 - 程式碼可方便地用於訪問知識庫或支援內容。為了理解這一點為何如此有用,請考慮以下 Platform 啟動輸出:

[2008-04-29 12:12:01.124] main                     <SPKB0001I> Platform starting.
[2008-04-29 12:12:04.037] main                     <SPKE0000I> Boot subsystems installed.
[2008-04-29 12:12:06.013] main                     <SPKE0001I> Base subsystems installed.
[2008-04-29 12:12:07.396] platform-dm-1            <SPPM0000I> Installing profile 'web'.
[2008-04-29 12:12:07.674] platform-dm…

Web 應用程式和 OSGi

工程 | Costin Leau | 2008 年 4 月 29 日 | ...

自 Spring Dynamic Modules 的第一個里程碑以來,執行 OSGi 中 Web 應用程式的請求開始湧入。這可能是最受歡迎的功能之一,而且毫不奇怪,一旦 1.0 最終版釋出,Web 支援就一直是 1.1 分支的主要關注點。我很高興地報告,隨著剛剛釋出的 M2,正如 Juergen 已經暗示的那樣,Spring-DM 不僅支援標準的 war(自 1.1.0 M1 起可用),還支援在 OSGi 中執行的 Spring-MVC 應用程式。在本文中,我想簡要討論典型的 OSGi Web 場景和 Spring-DM 的方法。但首先,

為什麼要在 OSGi 中部署 WAR?

簡單問題:OSGi *原生* 提供版本控制、包連線和熱重載入。想象一下在您的應用程式中利用這些功能:您可以停止將庫嵌入WEB-INF/lib並將它們在 Web 應用程式之間共享,避免 taglibs 重複(同時保持多個版本執行),並即時更新應用程式的特定部分。這尤其有用,因為 Web 應用程式往往是分層的,因此在其生命週期中會經歷大量更改。

為什麼 OSGi 中的 Web 應用程式存在問題?

Servlet 規範圍繞著一個*Web 容器*的概念:一個為 Web 元件提供執行時環境的執行時環境,該環境提供標準服務,如生命週期管理(物件建立和處置、執行緒分配)、併發、HTTP 請求處理等。另一方面,OSGi 平臺也作為具有服務登錄檔、包連線和版本控制(僅舉幾例)的託管環境。為了解決這個問題,OSGi 委員會設計了 compendium 規範的一部分,即 Http Service

如今,可移植性比以往任何時候都更重要

工程 | Juergen Hoeller | 2008 年 4 月 29 日 | ...

昨天,我寫了一篇關於Spring 如何幫助最大化應用程式可移植性的部落格。儘管可移植性問題一直是企業 Java 領域的一個持續性話題,但這篇部落格非常及時。今天,Oracle 宣佈其以 67 億美元收購 BEA Systems 的交易已完成。兩家公司產品集存在大量重疊,因此這必將為 WebLogic 和 OC4J 的客戶群帶來不確定性。WebLogic 和 OC4J 可能都屬於“J2EE 伺服器”類別,但它們是截然不同的產品,具有截然不同的特性。

由於許多企業……

框架層面的可移植性

工程 | Juergen Hoeller | 2008 年 4 月 28 日 | ...

可移植性是 Spring 生態系統的關鍵因素。我們相信框架層面的可移植性:應用程式元件是針對特定框架(或框架代)編寫的,例如 Spring 2.5;然後框架負責適應任何底層託管環境。然而,特定的應用程式框架獨立於託管環境。只要託管環境的基本功能足夠,就可以將一個全新的框架版本部署到一個已建立的託管平臺代上。這種方法……

會議季仍在繼續

工程 | Rod Johnson | 2008年4月24日 | ...

昨天,我在德國威斯巴登舉行的 JAX 會議 上發表了開幕主題演講。JAX 是歐洲最大的 Java 會議之一,有超過 2000 名與會者。主題是企業 Java 的未來,我詳細闡述了我 最近一篇關於預測的博文 中的主題,並深入探討了 Java EE 6 的影響 以及應用程式伺服器的未來。
我已 上傳了幻燈片,其中包括對企業 Java 演進過程中一段有趣時期的 8 項預測。這是我第一次在同一場演講中提及約瑟夫·斯大林、莫妮卡·萊溫斯基和蒙提·派森。

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有