Spring Framework 與 Hibernate 閒聊

Ching Yi, Chan
11 min readJun 19, 2021
timeline

在這求職的旺季謀求一份 Java 後端的工作時,最常會被問到的問題之一就是有沒有 Spring 與 Hibernate 的使用經驗,或是作為一個新人求職者程度上的鑑別提問。

對學習 Spring Framework (或 Spring Boot) 與 Hibernate 時間不長的開發者來說,僅有的經驗多半是跟著教學文件刻出了上面的內容,也許是成功印出 Hello World 之類的功能。然後,建立了許多的 class 加了不少的 annotation 這樣子的印象。

上述的微少經驗不足以來描述常見的面試提問:「談談什麼是 Spring 跟 Hibernate 唄?他們有什麼異同?」知情者會知道,把二個不同用途的東西放在一起比較很怪,但這是留個「眼」讓面試者反駁用的。若參與面試的人沒有明確切出一條線來,那肯定是對其中一項或完全沒有概念的情況了。

Java 標準與產品的進展

當我們要研究某個產品或解決方案是什麼時,一個適當的著眼點是:「在那個時空下,缺乏它的人們遇到了什麼困擾?」或是「當人們有了它之後,生活或工作上帶來了什麼改變?」

附圖最下方的時間軸 (它不是一個線性的刻度,我只是用它來表達時間的先後) 是 Java 產品線的進展。在 2002 年 2 月 Java SE 1.4 釋出,這是我初學 Java 時用的版本,隨後在 2004 年的 9 月 Java SE 5 釋出。在這前後「版號」有了重大的變化,不再以 1.x 進版,而是整數版號進版。

Java SE 5 有個重大的改變,那就是 Java Metadata 功能隨著它推出了。說到 Java Metadata 大家肯定陌生,因為在多數的開源專案文件都是描述為 Java Annotation,是用它的「語法特徵」來別述它,而不是以功能名稱來描述。

你可以看到在 Java 1.4 SE 與 Java 5 SE 之間有一條橘線隔出了時間軸的前後,在那之前我填上了 Java loved XML 在那之後寫著 Java supports @Annotation 。這功能對後續的應用程式框架或是函式庫的開發有著重大的改變。在那之前,應用程式的設定 (Configure) 大多集中在數個 XML 檔案之中。在那之後,設定的方式是用少量的 Property File 與 Java Annotation 來組成。

Java Annotation 解放的不只是大量依賴 XML 的設定,而是它解放了設計上對於完整「合約」的依賴。在沒有 Annotation 之前,要滿足「合約」或協議就只能要求開發者去實作特定的 interface。在有了 Annotation 之後,開發者只需要在約好的情境下標注即可。

以 Spring 3.x 版為例,當時的 Bean LifeCycle Callback 可以這麼寫:

有了 Annotation 後,不再強制實作 interface,讓設計更為鬆綁:

這些好用的設計在後續的 EJB 3 時代都被廣泛採納,他雖然不是推昇 EJB 3 的主因,但是是簡化產品設計的重要推手。而 EJB 3 標準的推出是官方規格與社群期望互相衝擊下的產物。在 EJB 3 出來之前的 EJB 1 與 EJB 2,偶爾被戲稱為 Java 開源社群的推手。因為笨重的設計,催生出了數個重量級的開源專案。例如我們正要談的 Hibernate 與 Spring Framework。

Enterprise JavaBean (EJB)

EJB 是 JavaEE 中相當重要的部分,但對現今多數的開發者來說,他是陌生的一塊。但若將時間軸回推到 1999 年末,那時還沒有 Hibernate 也沒有 Spring Framework。官方的標準是主流的技術選擇。EJB 提供 3 種類型的 Enterprise JavaBean:

  • Session Bean:用來實作通用的 Business Logic
  • Entity Bean:用來實作資料持久化的功能 (也就是把資料存入關聯式資料庫)
  • Message Driven Bean:用來實現事件驅動的開發模式

而 EJB 容器是一個分散式的架構,所以實作的時候開發者要提供:

  • EJB 實作本身 (上述某一種類型的 Bean)
  • 提供 EJBObject 介面
  • 提供 EJBHome 介面

我們採用 Oracle Archive 中的教學手冊與經典的 PetStore 專案作為接下來的範例,你可以至網站上下載:https://www.oracle.com/java/technologies/java-archive-eedocs-downloads.html

以《Java 2 Platform, Enterprise Edition Tutorial 1.3》提供的購物車案例來說,要提供 Business Logic 的 interface Cart 並實作 EJBObject:

它還需要有個 EJBHome 的 interface,這是被用來建立實體的 CartBean 用的:

真實的實作必需實作 SessionBean,它主要責任是滿足 Business Logic,並混雜 EJB 需要的 method:

如果你看完了 Session Bean 的實作已經覺得麻煩了,若是看到 Entity Bean 的實作方式就能體會到當時的開發者們的挫折感,若對於 Entity Bean 的實作有興趣,可下載 《Java Pet Store Demo 1.3.2》參考 PurchaseOrderEJB 相關的實作。由於 EJB 1 與 EJB 2 讓多人那麼挫折,不同的解決方式被大量提出,這也為什麼我們可以笑稱 EJB 真是開源專案的背後推手。

Hibernate

hibernate

http://www.javaperformancetuning.com/news/interview041.shtml

Hibernate was designed as a fix for the well known problems of Entity Beans. I was developing J2EE applications with an Australian company called Cirrus Technologies and was very frustrated by my lack of productivity, and by my inability to apply object modeling techniques to the business problem. I ended up spending more time thinking about persistence than I spent thinking about the user’s problem. That’s always wrong.

時間軸攤開,Hibernate 初次發佈是在 2001 年 5 月,在那年代的 Java EE 對於資料持久化的方案為 EJB 的 Entity Beans。在 Hibernate 創始者 Gavin King 的訪談中提到,他對於使用 Entity Beans 處理資料保存感到相當挫作,因為他沒辦法讓開發的心力專注在處理客戶的問題,大把的時間被花在撰寫 Entity Bean,這種乏缺生產力的開發體驗讓他覺得相當灰心。

Hibernate 的出現優雅地解決了資料持久化的問題與支持開發者能以「物件建模」的思維。它實現的是 Object Relational Mapping (ORM) 持術,透過一個中介的「方言」系統來媒合 Java 型別系統與 SQL 型別系統,讓 Java 開發者專案在處理 Object Model 對應的問題領域。較少的時間處理 SQL 語法與資料轉換的細節。

Hibernate 推出後廣受好評,在 Java 社群中有很高的人氣,這樣實績的口碑形成了推力,促使著 Java 標準修訂時向 Hibernate 的實作方式靠攏。Gavin King 本身也加入了規格制定的委員會。促成了 Java Persistence API (JPA) 在 EJB 3 取代了原先笨拙臃腫的 Entity Bean 實作方式。你可以簡單地想,JPA 是將原有的 Hibernate 功能轉換成官方的標準規格,但對於 JPA 制定內容仍需要有各方的共識才能促成的。

Hibernate 在 3.2 版開始支援 JPA,約在 3.4 版時成為正式相容 JPA 1.0 的 JPA Provider。JPA Provider 即為實作 JPA 介面的成品。除了 Hibernate 之外,巿面上有許多選擇。例如:EclipseLink

Spring Framework

Spring Framework 的出現較 Hibernate 晚了幾年。如果你曾好奇地查閱 Spring Framework 創始人 Rod Johnson 寫的書《Expert One-to-One J2EE Development》上面是這麼介紹的:

Expert One-on-One J2EE Development without EJB shows Java developers and architects how to build robust J2EE applications without having to use Enterprise JavaBeans (EJB). This practical, code-intensive guide provides best practices for using simpler and more effective methods and tools, including JavaServer pages, servlets, and lightweight frameworks.

這本書是在教導開發者們,在不使用 EJB 的情況下,開發 Java EE 應用程式。僅僅透過 Java EE 中的 JSP、Servlet 與「輕量級的框架」。我想這些大概就是 Spring Framework 被創造的契機了。而要描述 Spring Framework 本身是什麼?那就是他想要做到原本能在 Java EE 內做的事情,但把它變得更簡單,更加地簡化了。

Spring Framework 被社群廣為接納,不單純是減化了開發上的負擔,還有部署目標只需要有 Servlet Container 就行了,不一定需要 Application Server 才能使用。舉例來說:像 Apache Tomcat 就是個廣泛被使用的 Servlet Container,而 Weblogic 就是個能運作 EJB 的 Application Server。這也會造成營運成本上的節省。

回到技術本質,Spring Framework 著眼於原本開發 Java EE 應用程式上的痛點,使用 IoC Container 取代原先的 JNDI 查詢獲得 EJB 物件的方式。只要在設定檔上訂定好物件圖譜,那就能透過 IoC Container 建立出適當的物件。

以 EJB 為例。ConverterClient 是使用 JNDI 查詢取得 ConverterHome,並利用 ConverterHome 建立出對應的 Converter 使用的範例 (我們能知道它背後是呼叫 ConverterBean):

這樣的型式其實是使用 Service Locator 的方式取得服務,可以自製 Helper Class 將它簡化。而 Spring Framework 初期採用的是 Setter Injection 的方式,只要在 Class 中提供一個 Setter 讓 IoC Container 幫你設定物件即可。Spring Framework 提出的各種友善開發環境的作法,如同 Hibernate 在社群中獲得許多支持。各種促使 Java EE 進步的聲浪一同促成了後續的 EJB 3 標準的制訂。

IoC 與 Dependency Injection

在閒聊 Spring 1 至 Spring 2 中間進展的同時,Java 社群還有另一個熱衷的主題 (今天不是要講人人都想要做一個 Web Framework),而是各種大大小小專案都想搞自己的 Dependency Injection 機制。正式的正名出自於 《Inversion of Control Containers and the Dependency Injection pattern》,現存還留著當時記錄的大概剩 Pico Container 網頁中談 IoC 的歷史 能查到:

這小段僅作為記錄當時的趣事而寫,細節的內容可至 Pico Container 網頁繼續閱讀。

--

--