1. EJB 使用註解來表示元資料。Spring 使用 XML。
會上提到 Spring 開始支援更多註解,但“還需要一段時間”。然而,Spring 2.0 版本提供了完整的 JPA 整合,使用 @PersistenceContext 註解來注入 EntityManager,並提供了註解驅動的事務管理,使用 Spring 的 @Transactional 註解(支援與 @Stateless EJB 相同的語義,預設傳播級別為 REQUIRED)。我特別感到失望的是,比較中沒有在雙方都包含 JPA(見下文第 3 點)。Spring 2.0 還引入了完整的基於註解的 AspectJ 支援(@Aspect、@Before、@After、@Around)以及“構造型”註解的概念。例如,@Repository 註解為直接使用 JPA 或 Hibernate API 的資料訪問程式碼(無需 Spring 的模板)提供了非侵入式的異常翻譯。Spring 早在 1.2 版本就提供了註解支援,例如 @ManagedResource,用於透明地將任何 Spring 管理的物件匯出為 JMX MBean。
對我來說,這個問題排在第一位的主要原因是“這需要他們一段時間”的評論。作為 Spring 2.5 註解驅動配置支援的主要開發者之一,我必須說 Spring 元模型非常靈活,因此我們能夠比預期的更快地提供一個全面的基於註解的模型。事實上,Spring 2.5 支援 JSR-250 註解:@Resource、@PostConstruct 和 @PreDestroy,以及 @WebServiceRef 和 @EJB。特別有趣的是 @Resource,因為它是 EJB 3 中用於依賴注入的主要註解。在 Spring 中,@Resource 註解不僅支援 JNDI 查詢(如 EJB 3),還支援注入**任何 Spring 管理的物件**。這有效地結合了這次演講中提到的主要 Spring 優勢(Spring 支援任何型別的物件 DI)和主要 EJB 3 優勢(使用註解而不是 XML)。Spring 2.5 還引入了一個更細粒度的基於 @Autowired 和(可擴充套件的)@Qualifier 註解的註解驅動的依賴注入模型。Spring 2.5 還擴充套件了“刻板印象”註解,包括 @Service 和 @Controller。每個刻板印象註解都透過將其作為元註解來擴充套件通用的 @Component 註解。透過應用相同的技術,@Component 註解為使用者定義的刻板印象提供了擴充套件點。Spring 甚至可以自動檢測這些註解的元件,作為 XML 配置的替代方案。例如,這個片段摘自 2.5 版的 PetClinic 示例應用程式。
<context:component-scan base-package="org.springframework.samples.petclinic.web" />
由於 Web 控制器使用了註解驅動的依賴注入和用於請求對映的註解,因此不需要額外的 XML。我之所以指出這一點,是因為演講特別強調了 Web 層的配置的冗長。
@Controller
public class ClinicController {
private final Clinic clinic;
@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
...
有關 Spring 註解支援的最新介紹,請參閱:The Server Side 上的 Spring 2.5 入門教程,或最新版本的 Spring 參考手冊 - 特別是基於註解的配置部分。此外,請繼續關注本部落格和 Spring Framework 主頁,瞭解即將釋出的關於 2.5 版的文章和部落格。
2. Spring 允許您支援多種部署環境,但需要更多配置。
這實際上被 presenters 作為一個 Spring 的優勢來介紹,但強調了配置的開銷。事實是,任何認真對待測試和敏捷開發的專案的都將需要支援“多種部署環境”。換句話說,這個特定主題經常被曲解,好像它只適用於多種*生產*環境。實際上,在每個開發和測試周期中都部署到應用伺服器會是敏捷性的一個重大障礙。通常,Spring 使用者會模組化其配置,以便“基礎設施”配置(例如 DataSource、TransactionManager、JMS ConnectionFactory)是獨立的,並且動態屬性被外部化。由於 Spring 支援根據外部化屬性替換 '${placeholders}',因此包含不同的屬性檔案通常會變成一個透明的問題。
3. EJB 使用 JPA,Spring 使用 Hibernate
我必須承認,這最讓我惱火。在比較幻燈片中,EJB 3 示例顯示了使用*entityManager*進行資料訪問的 JPA,並且*entityManager*例項是透過 @PersistenceContext 註解提供的。另一方面,Spring 示例使用了 Hibernate,並顯示了 Hibernate SessionFactory 的 setter 注入。在我看來,這違反了真正“比較分析”的第一條規則:使用比較雙方最相似的功能。在這種特定情況下,Spring 確實支援直接使用 JPA API(即 JpaTemplate 完全是可選的;“entityManager”的直接使用仍然參與 Spring 事務等),並且 Spring 也識別 @PersistenceContext 註解。自從 Spring 2.0 以來(最終釋出已有一年多),一直提供此支援,因此我不明白為什麼比較不也使用 Spring 端的 JPA。比較的其他部分顯然基於 Spring 2.0,這給人一種選擇性過時和暴露偏見的印象。如果這個特定的例子被修改為“同類比較”,它將破壞一個主要的總體主題:Spring 需要更多配置,而 EJB 3 依賴於標準註解。
現在,儘管我認為在 Spring 端使用 Hibernate 而不是 JPA 扭曲了比較,但它同時也揭示了 Spring 的一個優勢。如果您確實想直接使用 Hibernate API 而不是依賴 JPA API,Spring 支援這一點,並且它在 Spring 事務管理和異常翻譯方面以一致的方式實現。這就有機會使用超越 JPA 限制的 Hibernate 功能,例如 Hibernate 的“criteria”查詢 API。同樣,如果您想新增一些直接的 JDBC 進行資料訪問,而 ORM 是過度的話,Spring 也支援這一點——即使是在與 Hibernate 或 JPA 資料訪問相同的事務中呼叫。
4. Spring 不做任何假設,您必須提供配置。
一個具體的例子是事務管理器的定義。有人說您必須瞭解容器供應商級別的知識才能配置 Spring 整合。這是不正確的。例如,以下 bean 定義不包含任何特定於容器的資訊,但 Spring 將自動檢測所有 Java EE 應用伺服器中的事務管理器。
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
如果您確實想利用特定於容器的功能,例如每個事務的隔離級別,那麼 Spring 也提供了一些專門的實現:*WebLogicJtaTransactionManager*、*WebSphereUowTransactionManager* 和 *OC4JJtaTransactionManager*。切換這些實現之間只需更改這一個定義。
除此之外,Spring 的配置幻燈片不必要地冗長。我擔心這也可能是出於強調 EJB 與 Spring 不同,依賴於智慧預設值的目的。例如,幻燈片顯示了
<tx:annotation-driven transaction-manager="transactionManager"/>
實際上,如果 Spring 上下文中只定義了一個 'transactionManager',那麼 'annotation-driven' 元素上就不需要顯式提供該屬性。該屬性僅用於啟用在一個應用程式中*如果需要*使用多個事務管理器。這些“自動檢測”和“智慧預設”技術貫穿於 Spring,例如訊息偵聽器的 JMS 'connectionFactory'(在下面的示例 #6 中有體現)以及現有 MBean 伺服器或 RMI 登錄檔的自動定位。
從積極的方面來看,它實際上被提到是 Spring 允許“本地”事務管理的一個優勢。雖然 EJB 需要 JTA 進行事務管理,但許多應用程式不需要跨兩階段提交能力資源進行分散式事務。在這種情況下,Spring 允許使用更簡單、開銷更低的事務管理器:DataSourceTransactionManager(用於 JDBC)、HibernateTransactionManager 或 JpaTransactionManager。如果目標是準確描述優缺點,我本應聽到更多關於 Spring 這一特定優勢的細節。例如,這對於在容器外進行測試或在 Eclipse 或 IDEA 等輕量級 IDE 環境中開發是一個巨大的好處。
此外,如果您確實需要 JTA 進行分散式事務,但又想在 Tomcat 或 Jetty 等輕量級容器中執行,Spring 可以輕鬆支援 Atomikos 和 JOTM 等獨立的 JTA 提供商。當然,Spring 的事務管理器設定需要配置一個*單個* bean 定義,但這確實是一次性成本——但絕對值得。
5. Spring 沒有有狀態應用程式範例。
無狀態服務層的優點作為最佳實踐已經相當確立,Spring 也採納了這一點。然而,Spring 確實提供了單例以外的範圍。Spring 的“prototype”範圍為每次注入或查詢提供了一個獨立的例項,Spring 2.0 引入了 Web 範圍:“request”和“session”。範圍機制本身甚至可以擴充套件;可以定義自定義範圍並將其對映到對話的概念。Spring 還支援使用 CommonsPoolTargetSource 進行簡單的物件池,但物件池很少是狀態管理的最佳解決方案。
更重要的是,Spring 透過 Spring Web Flow 為 Web 應用程式提供了非常健壯、高度可配置的狀態管理。在那裡,對話狀態是透明管理的,這與本次演講中聲稱的開發人員必須直接與 HTTP Session 互動來管理 Spring 應用程式狀態的說法相反。此外,儲存庫配置是可插拔的,因此可以使用各種策略來物理儲存狀態(session、client、後端快取等)。最後,Spring Web Flow 的最新發展包括對擴充套件持久化上下文的支援以及對 JSF 的完全整合支援。
6. Spring 需要為每個 MessageListener 配置一個容器。
Spring 2.5 提供了一個新的 'jms' 名稱空間,以大大簡化訊息偵聽器的配置。請注意,沒有為每個偵聽器配置單獨的容器。多個偵聽器共享配置,並且廣泛使用了智慧預設值。
<jms:listener-container>
<jms:listener destination="queue.confirm" ref="logger" method="log"/>
<jms:listener destination="queue.order…