Java 不爛 - 玩轉 JVM

工程 | Brian Dussault | 2015年2月11日 | ...

最近,James Ward 寫了一篇很棒的部落格文章,“Java 不爛 – 你只是用錯了”,其中重點介紹了企業級 Java 開發者在日常構建 Java 應用時面臨的諸多挑戰。好訊息是,擺脫開發困境比你想象的要容易得多。在過去幾年裡,Spring 重新定義了現代 Java 應用的構建方式,同時顯著提高了開發效率。在這篇文章中,我將以 James Ward 的部落格文章為背景,解釋 Spring 如何幫助開發者(使用 Java)玩轉 JVM,同時解決 James 提出的每一個問題。

##即時開發環境搭建太棒了 在 James 的部落格中,他斷言“設定開發環境需要 10 頁 Wiki 太糟糕了”。我們職業生涯中都曾建立過這些 Wiki 頁面,並努力嘗試保持其更新。這些 Wiki 長期以來一直是新團隊成員的沮喪來源,因為它們常常充斥著過時的資訊。好訊息是,Spring Boot 的構建支援使得自動化這一過程變得相當容易。

從現有應用開始,只需克隆原始碼倉庫並執行應用即可。Spring Boot 支援 Java 最流行的構建工具 Maven 和 Gradle。使用你喜歡的構建工具執行一個功能齊全的應用就這麼簡單:

Maven 示例

mvn spring-boot:run

Gradle 示例

gradle bootRun

由於 Spring Boot 應用是一個自包含的工作負載,將應用程式碼、伺服器和第三方依賴項組合成一個構建和部署單元(可執行的 .jar 檔案),因此無論使用何種 IDE,開發團隊都能獲得直接、可重複的開發體驗。開發者擺脫了繁瑣的環境設定說明,可以專注於構建出色的應用。在構建過程之外執行 Spring Boot 應用可以透過執行以下命令實現:

java -jar target/my-application-1.0.1-SNAPSHOT.jar

提示:想自己嘗試一下?請按照 spring.io 上的眾多入門指南之一進行操作。對於剛接觸 Spring Boot 的開發者來說,一個很好的起點是使用 Spring Boot 構建應用指南。

##一致的部署環境太棒了 James Ward 強調的下一個挑戰是“為了最大限度地降低將構建從開發環境推送到預生產環境再到生產環境的風險,唯一應該在各個環境之間變化的是配置”。手動修改部署工件是災難的根源,最終會導致部署延遲或失敗。特定於環境的配置應該外部化,確保在開發環境中測試的程式碼是最終將進入生產環境的“黃金副本”。這是證明您測試的內容就是您部署的內容的唯一經濟有效的方法!

Spring Boot 透過一種非常特定的 PropertySource 順序,使得外部化配置變得輕而易舉,這種順序旨在允許合理地覆蓋值。通常希望在專案中提供用於本地開發的預設配置,但在跨環境推廣程式碼時覆蓋這些值。Spring Boot 透過命令列引數、JNDI 屬性、Java 系統屬性、作業系統環境變數、配置檔案、基於 Profile 的配置變體以及更多方式為外部化配置提供了全面的支援。Spring Boot 對環境變數的支援使得遵循十二要素應用配置最佳實踐(程式碼與配置嚴格分離)變得輕而易舉。

提示 1:在使用 Cloud Foundry 等雲平臺時,Spring Boot 應用可以利用Spring Cloud Connectors 自動繫結到 Cloud Foundry 服務,如資料庫和訊息系統。這樣做的好處是減少了應用需要維護的環境特定配置屬性的數量,顯著降低了在跨環境推廣程式碼時出錯的風險。

提示 2:想知道為什麼十二要素應用很重要嗎?請檢視這篇部落格文章:為什麼十二要素應用模式、微服務和 CloudFoundry 很重要

##快速的伺服器啟動太棒了 Spring Boot 支援輕量級、嵌入式容器/伺服器,它們可以快速啟動。一個簡單的 REST 應用可以在短短 3 秒內啟動。從 Spring Boot 1.2 開始,支援嵌入式應用伺服器包括 Tomcat(預設容器)、Jetty 和 Undertow。Spring Boot 不僅支援領先的輕量級容器,而且透過使其易於替換預設容器,讓開發者完全掌控這些決策。

以下 Gradle 構建配置啟用了全棧 Web 開發支援,包括嵌入式 Tomcat 和 spring-webmvc 的支援。

Gradle 示例

...

apply plugin: 'java'

repositories { jcenter() }
dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:1.2.0.RELEASE")
}

...

正如 James Ward 在其原始部落格文章中所指出的那樣,透過將單體部署拆分為微服務,啟動時間可以得到進一步改善。在本文後面,將進一步詳細討論微服務的主題(請參閱標題為 微服務風格架構太棒了 的部分)。

受管理的依賴項太棒了

現代開發者需要能夠讓他們快速上手且阻力最小的工具和技術。他們還要求模組化、輕量級且具有明確觀點的技術來最佳化生產力。Spring Boot 正是針對快速啟動和執行的問題,同時顯著提高了開發速度。

正如 James Ward 正確指出的那樣,“如果你的任何庫依賴項不是由構建工具管理的,那太糟糕了”。Spring Boot 不僅支援現代構建技術,還提供了名為Starter POMs 的便捷依賴項描述符,從而將這一最佳實踐變為首要實踐。Starter POMs 為常見的開發工作負載提供了一組依賴項,你可以直接將其包含在你的應用中。

要開始使用 Spring Boot,你可以將瀏覽器指向 Spring Initializr - http://start.spring.io。Spring Initializr 提供了一個基於 Web 的介面,允許開發者選擇應用/工作負載和相關依賴項。然後,它將生成一個帶有構建支援的入門應用(支援 Maven POM、Maven 專案、Gradle 配置、Gradle 專案)。

Spring Initializr 截圖:Spring Initializr 截圖

對於喜歡命令列的開發者,您可以透過執行以下命令安裝 Spring Boot CLI:

curl http://start.spring.io/install.sh | sh

可以透過簡單地執行以下命令來使用命令列初始化新專案:

spring init --dependencies=web,data-jpa my-project

此初始化(透過 Spring Initializer 或 Boot CLI)的結果是一個完全可用的應用,其中所需的依賴項已被包含並由 Spring Boot 自動配置。

Spring IO Platform(包括 Spring Boot)也提供了 Spring Boot starter POMs 所管理的依賴項的超集。Spring IO 平衡了 Spring 產品組合中各依賴項的版本,並且釋出週期比 Spring Boot 更長,為企業提供了一個經過測試且已知可以協同工作的依賴項版本快照。Spring IO Platform 分發版不是一個巨大的庫下載包,開發者可以自由選擇應用中需要的任何部分。Spring IO 分發版包含 Spring 模組、測試庫、日誌框架、資料庫管理、SQL/No-SQL 等眾多元件的版本。Spring IO 分發版非常適合希望以更平緩的節奏使用 Spring IO Platform 依賴項的企業。

以下 Gradle 配置演示瞭如何配置 Spring IO Platform 的物料清單 (bill-of-materials) 並利用 Spring Boot 的 web starter POM


buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'io.spring.gradle:dependency-management-plugin:0.3.0.RELEASE'
    }
}

apply plugin: 'io.spring.dependency-management'

repositories {
    mavenCentral()
}

dependencyManagement {
    imports {
        mavenBom 'io.spring.platform:platform-bom:1.1.0.RELEASE'
    }
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web'
}

##短開發/驗證週期真的很棒 大多數現代應用都構建有富使用者介面,與後端服務通訊。以這種方式構建應用的好處在於 UI 和伺服器端邏輯之間實現了良好的關注點分離。大多數現代 IDE 都提供靜態資源的動態過載,允許開發者無需重啟伺服器即可看到更改。

Spring Boot 還支援伺服器端模板技術,如 Thymeleaf、Freemarker 和 Groovy。Spring Boot 允許動態過載這些模板技術,而無需重啟伺服器。對於 Thymeleaf,只需在 application.properties 檔案中設定以下屬性即可實現:

spring.thymeleaf.cache: false

在伺服器端,將您的單體應用拆分為微服務將減少 Spring Boot 應用的啟動時間(由於使用了輕量級嵌入式容器,啟動時間已經相當快)。此外,Spring Boot 還支援測試工具的自動配置。啟用 Boot 的測試自動配置就像包含 spring-boot-starter-test starter POM 一樣簡單。這使得 Spring Test、JUnit、Hamcrest 和 Mockito 依賴項可用,從而輕鬆地將測試驅動開發 (TDD) 整合到日常工作流程中。TDD 使開發者能夠立即收到對其程式碼更改的反饋。

最後,JRebel 為類過載提供了全面的支援,支援 80 多種 Java 框架(包括 Spring)。請檢視 Josh Long 和 Adam Koblentz 主講的線上研討會 Spring Boot and JRebel 6 以獲取更多詳情。

##微服務風格架構太棒了 James 關於“單體釋出太糟糕了”的說法對於大型或複雜的分散式系統來說是正確的。大多數開發者希望以更迭代的方式(敏捷)工作並更頻繁地釋出。微服務風格的架構作為一種應對單體應用挑戰的方式越來越受歡迎。對於不熟悉微服務的人,Martin Fowler 在他的部落格中提供了對這種架構風格的出色描述。

在構建分散式應用(包括微服務風格應用)時,會出現許多常見的系統模式。Spring Cloud 透過提供開箱即用的服務來解決最常見的挑戰,從而使其易於採用這些模式。Spring Cloud 實現了諸如配置管理、服務發現、斷路器、智慧路由、微代理和控制匯流排等模式。Spring Boot 使將這些功能整合到您的應用中變得異常簡單。

例如,Spring Cloud Netflix 專案使得使用 Netflix 的 Eureka 搭建服務發現服務變得像這樣簡單:


@SpringBootApplication 
@EnableEurekaServer

public class Application {
    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

客戶端應用只需使用 @EnableEurekaClient 即可註冊為 Eureka 客戶端。


@SpringBootApplication
@EnableEurekaClient
@RestController
public class Application {

    @RequestMapping("/")
    public String home() {
        return "Hello world";
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

提示 1:Spring Cloud 支援多種分散式處理模式。為了幫助您入門,請檢視 Spring Cloud Samples GitHub 倉庫。Dave Syer 和 Spencer Gibb 在 SpringOne 的演講 Spring Cloud, Spring Boot and Netflix OSS 是理解和學習如何操作微服務風格架構的另一個絕佳途徑。

提示 2:如果您希望構建超媒體風格的 REST API,請務必檢視入門指南 使用 REST 訪問 JPA 資料Spring Data REST 將有助於加速您的服務開發。Spring Data REST 支援 SQL 和 No-SQL 倉庫。

擁有能夠讓您快速編寫微服務的技術只是成功的一半。開發者常常受到將程式碼部署到生產平臺中的各種延遲困擾。一些最常見的障礙包括手動部署、測試、基礎設施供應和服務供應。持續交付旨在自動化將程式碼推向生產環境的過程,同時最大限度地降低風險。這使得組織能夠對應用進行增量更改,使部署成為業務決策而非資源決策。這本身是一個很大的話題,但我強烈推薦 Matt Stine 的演講 使用 Spring 和 Cloud Foundry 為 PaaS 開發微服務,該演講出色地強調了將敏捷工程實踐與 Pivotal Cloud Foundry 的自動化相結合的益處。

##無狀態應用太棒了 James 指出,“粘性會話和伺服器狀態通常是扼殺效能和彈性的最佳方法之一。會話狀態(傳統 Servlet 意義上的)使得持續交付和水平擴充套件變得異常困難。”

從應用中移除會話狀態可以顯著簡化操作,允許應用在無需擔心丟失會話資料的情況下重新部署、終止或擴充套件。保留狀態存在有效的用例,例如共享認證狀態,但這種狀態應該持久化在應用外部(通常在高效能儲存庫中,如 NoSQL、分散式快取,甚至是記憶體資料儲存)。外部化應用狀態不必是一項繁重的工作,Spring Session 提供了通用基礎設施,使這一過程變得簡單且可移植。Spring Session 提供:

  • 以供應商中立的方式支援叢集
  • RESTful API 支援 - 支援在 Header 中使用會話 ID
  • 用於確定會話 ID 的可插拔策略
  • 在 WebSocket 活動時保持 HttpSession 活躍的支援
  • 支援基於 Redis 和 Hazelcast 的會話儲存
  • 在單個瀏覽器中管理多個併發會話的能力(例如,類似於支援多個 Google 賬號)

使用 Redis 配置 Spring Session 就像這樣簡單:

@EnableRedisHttpSession
public class Config {

    @Bean
    public JedisConnectionFactory connectionFactory() {
        return new JedisConnectionFactory();
    }
}

提示:Spring Session 1.0 最近已正式釋出 (GA),所以請嘗試Spring Session 示例來親身體驗。Dave Syer 最近發表了一篇題為API 閘道器模式:Angular JS 和 Spring Security 第四部分的部落格文章,其中詳細介紹了共享認證狀態的用例。強烈推薦閱讀!

最後,如果您正在使用 Pivotal Cloud Foundry,Cloud Foundry Java 構建包提供了另一種透過自動配置的 CF 會話狀態儲存來輕鬆外部化狀態的選項。請檢視這篇部落格文章瞭解詳情。

##非阻塞應用太棒了 許多現代應用架構可以從非同步和非阻塞請求處理中受益匪淺。這些用例可以包括組合多個後端服務呼叫和 WebSocket 風格的應用。

Project Reactor(Spring IO Platform 的一部分)為構建這些非同步、非阻塞應用提供了基礎。在 2.0 版本中,Reactor 將提供Reactive Streams 規範的完整實現,從而實現了與其他 Reactive Streams 實現(如 Akka StreamsRatpackRxJava)的整合。

以下程式碼片段展示瞭如何使用 Reactive Streams API 建立流、新增業務邏輯,然後向其中釋出資料:

// by default Streams use the Disruptor RingBufferDispatcher
Broadcaster<String> helloStream = Streams.broadcast(env);

helloStream.map(s -> "Hello " + s + "!")
           .consume(log::info);

helloStream.onNext("World");

提示:Spring Boot 支援 Project Reactor,使其易於入門。請按照使用 Reactor 建立非同步事件驅動應用入門指南來建立您的第一個響應式應用。此外,請務必檢視線上研討會:使用 Reactor 構建非同步、非阻塞微服務

Spring Framework 4 引入了對 WebSocket 風格的事件驅動應用的支援。這種務實的方法遠超 JSR-356 規範,包括透過 SockJS 提供客戶端回退選項、支援訊息子協議 (STOMP)、安全(Spring Security 4)、訊息代理支援、基於 Reactor 的 MessageChannel 用於訊息傳遞、客戶端斷開連線處理以及熟悉的 Spring 程式設計模型。

提示:Spring Boot 使 WebSocket 應用的配置變得輕而易舉。請按照使用 WebSocket 構建互動式 Web 應用指南來開始。

Java 語言太棒了

Spring Boot 為開發者提供了使用 Java 6、7、8 以及 Groovy 來構建下一代應用的選擇。在 James 的文章中,他提到“Java 語言有點糟糕”,但隨著 Java 8 的釋出,Java 得到了極大的推動,並提供了許多能夠提高生產力的強大語言特性。Java 8 的一些出色特性包括支援 Lambda 表示式、Stream 和併發改進。Spring Boot 使您輕鬆開始使用 Java 8 或 Groovy。

提示:如果您是 Java 8 特性的新手,我強烈推薦 Venkat Subramaniam 的書 Java 中的函數語言程式設計:利用 Java 8 Lambda 表示式的力量 以及他在 SpringOne2GX 2014 上的演講。

##結論 構建現代 Java 應用不必是一個痛苦的經歷。Spring Boot 已經消除了構建應用的繁瑣儀式,讓 Java 再次變得有趣。Spring 從您應用的每一層移除樣板程式碼——業務邏輯(Spring Foundation 專案)、配置和執行時(Spring Boot)以及分散式系統模式(Spring Cloud)。最佳入門方法是深入研究Spring 的入門指南,並部署到Pivotal Web Services(一個公共託管版本的 Cloud Foundry,可免費試用 60 天)。

獲取 Spring 資訊

訂閱 Spring 資訊,保持聯絡

訂閱

取得領先

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

瞭解更多

獲取支援

Tanzu Spring 在一個簡單的訂閱中提供對 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案。

瞭解更多

即將舉行的活動

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

檢視全部