1. EJB 使用註解進行元資料。Spring 使用 XML。
有人提到 Spring 正在開始支援更多的註解,但「他們需要一段時間」。但是,Spring 2.0 版本提供了完整的 JPA 整合,帶有 @PersistenceContext 用於注入 EntityManager,以及帶有 Spring @Transactional 註解的註解驅動的事務管理(支援與具有 REQUIRED 預設傳播的 @Stateless EJB 相同的語意)。我特別感到沮喪的是,該比較沒有在雙方都包含 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 的 metadata 模型非常彈性,因此我們能夠比預期更快地提供一個全面的基於註解的模型。事實上,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。每個刻板印象註解都透過將其作為 meta-annotation 應用來擴展通用的 @Component 註解。透過應用相同的技術,@Component 註解為使用者定義的刻板印象提供了一個擴展點。Spring 甚至可以自動偵測這些帶註解的元件,作為 XML 配置的替代方案。例如,這個摘錄取自 PetClinic 範例應用程式的 2.5 版本
<context:component-scan base-package="org.springframework.samples.petclinic.web" />
無需額外的 XML 用於 web 控制器,因為它們使用註解驅動的依賴注入和用於請求映射的註解。我指出這一點,是因為簡報特別強調了 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 允許您支援多個部署環境,但需要更多配置。
這實際上是作為 Spring 的優勢提出的,但強調了配置的開銷。事實是,任何認真對待測試和敏捷開發的專案都需要支援「多個部署環境」。換句話說,這個特定的主題經常被扭曲,好像它只適用於多個生產環境。實際上,在每個開發和測試週期中都必須部署到應用程式伺服器是對敏捷性的主要障礙。通常,Spring 使用者會將其配置模組化,以便「基礎架構」配置(例如 DataSource、TransactionManager、JMS ConnectionFactory)是獨立的,並且動態屬性是外部化的。由於 Spring 支援基於外部化屬性替換 '${placeholders}',因此包含不同的屬性檔案通常會變得透明。
3. EJB 使用 JPA,Spring 使用 Hibernate
我必須承認這一個最困擾我。在比較幻燈片中,EJB 3 範例顯示了透過 entityManager 進行資料存取的 JPA,以及使用 @PersistenceContext 註解提供的 entityManager 實例。另一方面,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 事務管理和異常轉換方面以一致的方式實現。然後,這就開啟了使用 Hibernate 功能的機會,這些功能超出了 JPA 的限制,例如 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 這一特定優勢的細節。例如,這對於在容器外進行測試或在輕量級 IDE 環境(例如 Eclipse 或 IDEA)中進行開發來說是一個巨大的好處。
此外,如果您確實需要 JTA 進行分布式事務,但想在像 Tomcat 或 Jetty 這樣的輕量級容器中運行,Spring 可以輕鬆支援像 Atomikos 和 JOTM 這樣的獨立 JTA 提供者。當然,Spring 的事務管理員設置需要配置單個 bean 定義,但這確實是一次性成本 - 並且非常值得。
5. Spring 沒有有狀態的應用程式範例。
無狀態服務層的優點已相當成熟,是一種最佳實踐,Spring 也接受這一點。但是,Spring 確實提供了單例以外的其他範圍。Spring 的「原型」範圍為每次注入或查找啟用一個不同的實例,而 Spring 2.0 引入了 web 範圍:「request」和「session」。範圍機制本身甚至是可擴展的;可以定義自定義範圍並將其映射到對話的概念。Spring 還支援使用 CommonsPoolTargetSource 的簡單物件池,但物件池很少是狀態管理的最佳解決方案。
更重要的是,Spring 透過 Spring Web Flow 為 web 應用程式提供非常強大、高度可配置的狀態管理。在那裡,對話狀態是透明地管理的,這與本次簡報聲稱開發人員必須直接與 HTTP Session 互動才能管理 Spring 應用程式中的狀態相反。此外,儲存庫配置是可插入的,因此可以使用各種策略來物理儲存狀態(session、客戶端、後端快取等)。最後,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…