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。
現在這個問題對我來說是 #1 的主要原因是評論說「需要一段時間」。 作為 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 配置。 例如,此摘錄取自 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 視為一種優勢,但強調其組態上的額外負擔。事實是,任何認真看待測試和敏捷開發的專案都需要支援「多個部署環境」。換句話說,這個特定主題經常被扭曲,好像它只適用於多個正式 (production) 環境。實際上,在每次開發和測試週期中都必須部署到應用程式伺服器,這對敏捷性來說是一個主要的障礙。通常,Spring 使用者會將他們的組態模組化,使得「基礎架構」組態(例如 DataSource、TransactionManager、JMS ConnectionFactory)是獨立的,並且動態屬性是外部化的。由於 Spring 支援基於外部化屬性替換 '${placeholders}',因此包含不同的屬性檔案通常會變成一個透明的問題。
3. EJB with JPA, Spring with Hibernate
我必須承認,這一個最讓我困擾。在比較投影片中,EJB 3 的範例顯示了 JPA,並透過 entityManager 進行資料存取,並且 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 可以輕鬆地支援獨立的 JTA 提供者,如 Atomikos 和 JOTM。當然,Spring 的交易管理器設定需要配置單一 bean 定義,但這確實是一次性的成本 - 而且非常值得。
5. Spring 沒有有狀態的應用程式典範。
無狀態服務層的優點已經被廣泛地確立為最佳實踐,而 Spring 也擁抱了這一點。然而,Spring 確實提供了單例 (singleton) 以外的其他 scopes。Spring 的 "prototype" scope 為每次注入或查找啟用一個不同的實例,而 Spring 2.0 引入了 web scopes:"request" 和 "session"。Scoping 機制本身甚至是可擴展的;可以定義一個自定義 scope 並將其映射到對話 (conversation) 的概念。Spring 還支援使用 CommonsPoolTargetSource 的簡單物件池,但物件池很少是狀態管理的最佳解決方案。
更重要的是,Spring 透過 Spring Web Flow 為 web 應用程式提供了非常強大、高度可配置的狀態管理。在那裡,對話狀態是透明地管理的,與此簡報聲稱的開發人員必須直接與 HTTP Session 互動以管理 Spring 應用程式中的狀態相反。此外,儲存庫組態是可插拔的,因此可以使用各種策略來物理儲存狀態(session、client、backend cache 等)。最後,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…