Groovy 使 Spring 更出色,第 1 部分: 集成的基礎知識

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  
Spring Framework 為 Web 和企業應用程序提供了堅實的基礎。通過支持 Groovy 等動態語言,Spring 添加了一些功能,從而使應用程序架構更加靈活、更具動態性。在包含 2 部分的系列文章 的第一部分中,您將學習將 Groovy 集成到 Spring 應用程序的基礎知識。

Spring 2.0 支持將動態語言集成到基於 Spring 的應用程序中。Spring 開箱即用地支持 Groovy、JRuby 和 BeanShell。以 Groovy、JRuby 或任何受支持的語言(當然包括 Java™ 語言)編寫的應用程序部分可以無縫地集成到 Spring 應用程序中。應用程序其他部分的代碼不需要知道或關心單個 Spring bean 的實現語言。

Spring 支持動態語言意味著應用程序可以獲得靈活性和動態性,並且沒有任何附加條件。在本系列的第 1 部分中,您將看到如何將 Spring 和 Groovy 一起使用,以及這個強大集成如何為應用程序增加有趣的功能。例如,您可能需要頻繁地更改小塊的業務邏輯、應用程序發出的 e-mail 消息中包含的文本、應用程序生成的 PDF 格式和布局等。為了進行更改,傳統的應用程序架構可能需要完全重新部署應用程序。Spring 支持 Groovy 之後,您可以這樣更改一個已部署的應用程序,並使這些更改立即生效。我將討論這一功能為應用程序所帶來的好處,以及可能引發的問題。本文中所有例子的完整的源代碼(參見 下載)都可以下載。

Spring 的動態語言支持

動態語言支持將 Spring 從一個以 Java 為中心的應用程序框架改變成一個以 JVM 為中心的應用程序框架。現在,Spring 不再只是讓 Java 開發變得更容易。它還允許將以靜態和動態語言編寫的代碼輕鬆地插入到 Spring 支持的分層架構方法中,從而使 JVM 的開發也變得更加容易。如果您已經熟悉 Spring,那麼您會感到很舒服:可以利用 Spring 已經提供的所有特性 — 控制反轉(IoC)和依賴項注入、面向方面編程(AOP)、聲明式事務劃分、Web 和數據訪問框架集成、遠程調用等 — 同時又可以使用靈活動態的語言,比如 Groovy。

Spring 通過 ScriptFactory 和 ScriptSource 介面支持動態語言集成。ScriptFactory 介面定義用於創建和配置腳本 Spring bean 的機制。理論上,所有在 JVM 上運行語言都受支持,因此可以選擇特定的語言來創建自己的實現。ScriptSource 定義 Spring 如何訪問實際的腳本源代碼;例如,通過文件系統或 URL。Groovy 語言集成通過 ScriptFactory 的 GroovyScriptFactory 實現得到支持。

為什麼是 Groovy?

根據官方的 Groovy 站點,Groovy 是 “用於 Java 虛擬機的一種敏捷的動態語言”,它 “以 Java 的強大功能為基礎,同時又包含由 Python、Ruby 和 Smalltalk 等語言帶來的強大附加功能”,例如動態類型轉換、閉包和元編程(metaprogramming)支持(參見 參考資料)。它是一種成熟的面向對象編程語言,既可以用於面向對象編程,又可以用作純粹的腳本語言。我喜歡將它看作是沒有討厭代碼,但又具有閉包和動態語言中的其他特性的 Java 語言。

Groovy 特別適合與 Spring 的動態語言支持一起使用,因為它是專門為 JVM 設計的,設計時充分考慮了 Java 集成,這使 Groovy 與 Java 代碼的互操作很容易。它的類 Java 語法對於 Java 開發人員來說也很自然。

接下來,看看如何將 Groovy 代碼集成到基於 Spring 的應用程序中。





更巧妙的 Spring bean

在 Spring 應用程序中使用 Groovy bean 很容易,就像使用 Java bean 一樣。(但是,在後面可以看到,對於如何配置它們,則有很多選項)。首先,需要定義一個介面作為 Groovy bean 必須遵從的約定。雖然不是非得定義介面不可,但是大多數 Spring 應用程序會通過介面(而不是具體實現類)來定義應用程序組件之間的交互和依賴項,以促進鬆散耦合併為測試提供便利。

例如,假設有一個定義如何從 Invoice 對象生成 PDF 的介面。如清單 1 所示:


清單 1. PdfGenerator 介面
				  public interface PdfGenerator {      byte[] pdfFor(Invoice invoice);  }  

PdfGenerator 介面被用作 Groovy 實現類必須遵從的約定。這很容易,因為 Groovy 類可以像 Java 類那樣實現介面。清單 2 顯示了 PdfGenerator 的 Groovy 實現,它使用 iText 庫(參見 參考資料)完成實際的 PDF 生成;它返回一個包含 PDF 內容的位元組數組:


清單 2. GroovyPdfGenerator
				  class GroovyPdfGenerator implements PdfGenerator {        String companyName        public byte[] pdfFor(Invoice invoice) {          Document document = new Document(PageSize.LETTER)          ByteArrayOutputStream output = new ByteArrayOutputStream()          PdfWriter.getInstance(document, output)          document.open()          Font headerFont = new Font(family: Font.HELVETICA, size: 24.0, style: Font.ITALIC)          document.add(new Paragraph("$companyName", headerFont))          document.add(new Paragraph("Invoice $invoice.orderNumber"))          document.add(new Paragraph("Total amount: \$ ${invoice.total}"))          document.close()          output.toByteArray()      }  }  

GroovyPdfGenerator 已準備就緒。它定義了一個名為 companyName 的 string 屬性,該屬性在生成的 PDF 發票上與訂單號和總額一起使用。此時,可以將 GroovyPdfGenerator 集成到 Spring 應用程序中。使用 Java 語言編寫的 bean 必須編譯成 .class 文件,但是在使用基於 Groovy 的 bean 時,則有幾種選擇:

  • 將 Groovy 類編譯成普通的 Java 類文件
  • 在一個 .groovy 文件中定義 Groovy 類或腳本
  • 在 Spring 配置文件中以內聯方式編寫 Groovy 腳本

可以選擇不同的方法在 Spring 應用程序上下文中定義和配置 Groovy bean,這取決於 Groovy bean 採用的選項。接下來,我們將探討每一種配置選項。





Groovy bean 配置

通常,可以使用 XML 配置用 Java 代碼編寫的 Spring bean,或者 — 從 Spring 2.5(參見 參考資料)開始 — 使用註釋進行配置,後者可以顯著減少 XML 配置。當配置 Groovy bean 時,可用的選項取決於是使用編譯的 Groovy 類還是 .groovy 文件中定義的 Groovy 類。需要記住的是,您可以使用 Groovy 實現 bean,然後可以像 Java 編程那樣編譯它們;或者在 .groovy 文件中以類似腳本的形式實現它們,然後由 Spring 負責在創建應用程序上下文時編譯它們。

如果選擇在 .groovy 文件中實現 bean,那麼您不必 自己編譯它們。相反,Spring 讀取文件,獲得腳本源代碼並在運行時編譯它們,使它們可用於應用程序上下文。這比直接編譯更靈活性,因為不一定必須將 .groovy 文件部署在應用程序的 JAR 或 WAR 文件中,它們還可以來自文件系統的某個地方或 URL。

接下來介紹各種不同的配置選項的應用。要記住在構建過程中自己編譯的 Groovy 類中定義的 bean 與在 .groovy 腳本中定義的 bean 之間的區別。

配置編譯的 Groovy 類

配置已經編譯成 .class 文件的 Groovy bean,這與配置基於 Java 的 bean 完全一樣。假設您已經使用 groovyc 編譯器編譯了 GroovyPdfGenerator,那麼可以使用常規的 Spring XML 配置定義 bean,如清單 3 所示:


清單 3. 使用 XML 配置預編譯的 GroovyPdfGenerator
				  <bean id="pdfGenerator" class="groovierspring.GroovyPdfGenerator">      <property name="companyName" value="Groovy Bookstore"/>  </bean>  

Groovy bean 上沒有基於構造函數的注入

不幸的是,目前還不能使用構造函數注入在 Groovy bean 上設置屬性(或任何其他動態語言 bean,比如 JRuby bean)。原因之一是腳本可以定義多個實現類和邏輯,以根據運行時環境或其他因素選擇不同的實現。換句話說,實際的構造是由腳本完成的,而不是 Spring。Spring 使用 setter 注入在返回的 bean 上設置屬性。清單 7 顯示了一個例子。

清單 3 中的配置是一個簡單的舊的 Spring bean 定義。它是用 Groovy 實現的,但這一點不重要。在包含 pdfGenerator bean 的 Spring 應用程序中,任何其他組件都可以使用它,而不必知道或關心它的實現細節或語言。還可以像往常一樣使用 <property> 元素在 bean 上設置屬性。(Spring 2.0 引入了 p 名稱空間,以便更簡練地定義屬性,但是我堅持使用 <property> 元素,因為我發現它們可讀性更好 — 這完全是個人的喜好)。

另外,如果使用 Spring 2.5 或更高版本,還可以使用基於註釋的 GroovyPdfGenerator 的配置。在此情況下,不必在 XML 應用程序上下文中實際定義 bean;相反,可以用 @Component 構造型註釋來註釋類,如清單 4 所示:


清單 4. 用 @Component 註釋 GroovyPdfGenerator
				  @Component("pdfGenerator")  class GroovyPdfGenerator implements PdfGenerator {      ...  }  

然後,在 Spring 應用程序上下文 XML 配置中啟用註釋配置和組件掃描,如清單 5 所示:


清單 5. 啟用 Spring 註釋配置和組件掃描
				  <context:annotation-config/>  <context:component-scan base-package="groovierspring"/>  

不管使用 XML 還是註釋來配置編譯后的 Groovy bean,這種配置與普通的基於 Java bean 的配置是一樣的。

配置來自 Groovy 腳本的 bean

配置來自 .groovy 腳本的 Groovy bean 與配置編譯后的 Groovy bean 大不相同。在這裡,事情開始變得更加有趣。將 Groovy 腳本轉換為 bean 的機制包括讀取並編譯 Groovy 腳本,然後使之可以在 Spring 應用程序上下文中作為 bean 使用。第一步是定義一個 bean,它的類型可以認為是 GroovyScriptFactory,並且指向 Groovy 腳本的位置,如清單 6 所示:


清單 6. 定義 GroovyScriptFactory bean
				  <bean id="pdfGenerator"        class="org.springframework.scripting.groovy.GroovyScriptFactory">      <constructor-arg value="classpath:groovierspring/GroovyPdfGenerator.groovy"/>      <property name="companyName" value="Groovier Bookstore"/>  </bean>  

在這個清單中,pdfGenerator bean 被定義為 GroovyScriptFactory。<constructor-arg> 元素定義要配置的 Groovy 腳本的位置。特別要注意,這指向一個 Groovy 腳本,而不是一個已編譯的 Groovy 類。可以使用定義 Spring bean 的語法設置用腳本編寫的對象的屬性。正如您預期的那樣,清單 6 中的 <property> 元素設置 companyName 屬性。

GroovyPdfGenerator.groovy 腳本 必須包含至少一個實現介面的類。通常,最好的做法是遵從標準 Java 實現,每個 .groovy 文件定義一個 Groovy 類。但是,您可能想在腳本中實現用於確定創建哪種類型的 bean 的邏輯。例如,可以在 GroovyPdfGenerator.groovy 中定義 PdfGenerator 介面的兩種不同的實現,並直接在腳本中執行確定應該返回哪種實現的邏輯。清單 7 定義兩種不同的 PdfGenerator 實現,並根據系統的屬性選擇使用一種實現:


清單 7. Groovy 腳本中的多個類定義
				  class SimpleGroovyPdfGenerator implements PdfGenerator {      ...  }    class ComplexGroovyPdfGenerator implements PdfGenerator {      ...  }    def type = System.properties['generatorType']  if (type == 'simple')      return new SimpleGroovyPdfGenerator()  }  else {      return new ComplexGroovyPdfGenerator()  }  

如這段代碼所示,可以通過用腳本編寫的 bean 根據系統屬性選擇不同的實現。當 generatorType 系統屬性為 simple 時,該腳本創建並返回一個 SimpleGroovyPdfGenerator;否則,它返回一個 ComplexGroovyPdfGenerator。由於簡單和複雜的實現都實現了 PdfGenerator 介面,因此 Spring 應用程序中使用 pdfGenerator bean 的代碼不必知道也不必關心實際的實現是什麼。

注意,仍然可以像 清單 6 那樣在從腳本返回的 bean 上設置屬性。所以,如果腳本返回一個 ComplexGroovyPdfGenerator,則設置該 bean 上的 companyName 屬性。如果不需要定義多個實現,那麼可以在 Groovy 腳本文件中僅定義一個類,如清單 8 所示。在這種情況下,Spring 發現並實例化這個惟一的類。


清單 8. 典型的 Groovy 腳本實現
				  class GroovyPdfGenerator implements PdfGenerator {      ...  }  

至此,您可能想知道為什麼 清單 6 將 bean 定義為一個 GroovyScriptFactory。那是因為 Spring 通過一個與 ScriptFactoryPostProcessor bean 結合的 ScriptFactory 實現(在這裡是一個 Groovy 工廠)創建腳本對象。ScriptFactoryPostProcessor bean 負責用由工廠創建的實際對象替換工廠 bean。清單 9 顯示添加后處理器 bean 的附加配置:


清單 9. 定義 ScriptFactoryPostProcessor bean
				  <bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>  

當 Spring 裝載應用程序上下文時,它首先創建工廠 bean(例如 GroovyScriptFactory bean)。然後,執行 ScriptFactoryPostProcessor bean,用實際的腳本對象替換所有的工廠 bean。例如,清單 6 和 清單 9 中的配置產生一個名為 pdfGenerator 的 bean,它的類型是 groovierspring.GroovyPdfGenerator。(如果啟用 Spring 中的 debug 級日誌記錄,並觀察應用程序上下文的啟動,將會看到 Spring 首先創建一個名為 scriptFactory.pdfGenerator 的工廠 bean,然後 ScriptFactoryPostProcessor 從該工廠 bean 創建 pdfGenerator bean)。

現在,您已知道使用 GroovyScriptFactory 和 ScriptFactoryPostProcessor 配置腳本編寫的 Groovy bean 的底層細節,接下來我將展示一種更簡單、更整潔的方法。這種方法可以得到相同結果。Spring 專門為創建腳本 bean 提供了 lang XML 模式。清單 10 使用 lang 模式定義 pdfGenerator bean:


清單 10. 使用 <lang:groovy> 定義腳本 bean
				  <lang:groovy id="pdfGenerator"               script-source="classpath:groovierspring/GroovyPdfGenerator.groovy">      <lang:property name="companyName" value="Really Groovy Bookstore"/>  </lang:groovy>  

這段代碼產生的 pdfGenerator bean 與 清單 6 和 清單 9 中更冗長的配置產生的 bean 是一樣的,但是它更整潔、更簡練,而且意圖更清晰。<lang:groovy> bean 定義需要 script-source 屬性;這告訴 Spring 如何找到 Groovy 腳本源代碼。此外,可以使用 <lang:property> 元素為腳本 bean 設置屬性。使用 <lang:groovy> 定義基於 Groovy 的 bean 是一種更好的選擇。對閱讀 Spring 配置的人而言,這種選項也更加清晰。

配置內聯 Groovy 腳本

為了實現完整性,我將介紹:Spring 還支持直接在 bean 定義中編寫 Groovy 腳本。清單 11 使用一個內聯腳本創建 pdfGenerator:


清單 11. 內聯定義腳本 bean
				  <lang:groovy id="pdfGenerator">      <lang:inline-script>          <![CDATA[          class GroovyPdfGenerator implements PdfGenerator {              ...          }          ]]>      </lang:inline-script>      <lang:property name="companyName" value="Icky Groovy Bookstore"/>  </lang:groovy>  

這段代碼使用 <lang:groovy> 和 <lang:inline-script> 標記定義 pdfGenerator bean,它包含定義類的 Groovy 腳本。可以像前面一樣使用 <lang:property> 設置屬性。您可能已經猜到,我不建議在 XML 配置文件中定義腳本 bean(或這一方面的任何類型的代碼)。

使用 Grails Bean Builder 配置 bean

Grails Web framework 在幕後依賴於 Spring。Grails 提供了 Bean Builder,這是一個很棒的特性,讓您可以使用 Groovy 代碼編程式地 定義 Spring bean(參見 參考資料)。編程式地定義 bean 比 XML 配置更靈活,因為可以在 bean 定義腳本中嵌入邏輯,而這在 XML 中是不可能的。通過使用 Bean Builder,可以為已編譯 Groovy 類和用腳本編寫的 Groovy bean 創建 bean 定義。清單 12 使用已編譯的 Groovy 類定義 pdfGenerator bean:


清單 12. 使用 Bean Builder 定義已編譯的 Groovy bean
				  def builder = new grails.spring.BeanBuilder()  builder.beans {      pdfGenerator(GroovyPdfGenerator) {          companyName = 'Compiled BeanBuilder Bookstore'      }  }  def appContext = builder.createApplicationContext()  def generator = context.pdfGenerator  

清單 12 中的代碼首先實例化一個 BeanBuilder,然後通過方法調用創建 bean。每個方法調用和可選的閉包參數定義一個 bean,並設置 bean 屬性。例如,pdfGenerator(GroovyPdfGenerator) 定義一個名為 pdfGenerator 的 bean,其類型為 GroovyPdfGenerator,閉包中的代碼則設置 companyName 屬性。當然,在 beans 閉包中可以定義多個 bean。

通過使用 Bean Builder,還可以從 Groovy 腳本而不是已編譯的 Groovy 類創建 bean。但是,Bean Builder 沒有 <lang:groovy> 配置中的語法糖(syntactic sugar,即在計算機語言中添加的某種語法,這種語法對語言的功能並沒有影響,但是更方便程序員使用),所以需要將 bean 定義為 GroovyScriptFactory,並創建一個 ScriptFactoryPostProcessor bean。清單 13 是一個例子,展示如何使用 Bean Builder 配置用腳本編寫的 Groovy bean:


清單 13. 使用 Bean Builder 定義用腳本編寫的 Groovy bean
				  def builder = new grails.spring.BeanBuilder()  builder.beans {      pdfGenerator(GroovyScriptFactory,                  'classpath:groovierspring/GroovyPdfGenerator.groovy') {          companyName = 'Scripted BeanBuilder Bookstore'      }      scriptFactoryPostProcessor(ScriptFactoryPostProcessor)  }  def appContext = builder.createApplicationContext()  def generator = context.pdfGenerator  

清單 13 中的代碼在邏輯上等同於 清單 6 和 清單 9 中的 XML 配置。當然,清單 13 是使用 Groovy 代碼來定義 bean。為了定義 pdfGenerator bean,清單 13 將類型指定為 GroovyScriptFactory。第二個參數指定腳本源代碼的位置,和前面一樣,在閉包中設置 companyName 屬性。它還定義一個名為 scriptFactoryPostProcessor 的 bean,其類型為 ScriptFactoryPostProcessor,它將用實際的用腳本編寫的對象替換工廠 bean。

哪種配置選項最好?

至此,您已經看到配置基於 Groovy 的 bean(無論是已編譯的還是用腳本編寫的)的幾種不同的方式。如果您僅是使用 Groovy 替代 Java 作為應用程序的主要語言,那麼配置這些 bean 與配置基於 Java 的 bean 沒有區別。對於已編譯的 Groovy 類,可以使用 XML 或基於註釋的配置進行配置。

對於用腳本編寫的 Groovy 對象,雖然可以用幾種不同的方式來配置它們,但是 <lang:groovy> 選項卻是最簡潔的方式,與使用 GroovyScriptFactory 和 ScriptFactoryPostProcessor 或者使用 <lang:inline-script> 進行配置相比,這種選項能夠最清晰地表現意圖。

您還看到了 Grails Bean Builder,它以完全不同的方式創建大多數 Spring 應用程序使用的 Spring 應用程序上下文。如果要用 Groovy 創建所有的 bean,並且要能夠添加邏輯到 bean 構建過程中,Bean Builder 必須很好地符合要求。另一方面,使用 Bean Builder 定義 Groovy bean 時,需要使用 GroovyScriptFactory 和 ScriptFactoryPostProcessor 來定義 bean。





使用 Groovy bean

bean 配置和可用的幾個選項是集成 Groovy 和 Spring 的難點(但是如您所見,這並不是很難)。實際上,在 Spring 應用程序中使用 Groovy bean 很容易。Spring 的動態語言支持使得 bean 的使用對於應用程序代碼是完全透明的,應用程序代碼不需要知道也不需要關心實現細節。您可以像平常開發 Spring 應用程序一樣編寫應用程序代碼,並且可以利用 Spring 提供的所有特性,例如依賴項注入、AOP 和與第三方框架集成。

清單 14 展示了一個簡單的 Groovy 腳本,它從 XML 配置文件創建一個 Spring 應用程序上下文,獲取 PDF 生成器 bean,並使用它生成一個發票的 PDF 版本:


清單 14. 在腳本中使用 Groovy bean
				  def context = new ClassPathXmlApplicationContext("applicationContext.xml")  def generator = context.getBean("pdfGenerator")    Invoice invoice = new Invoice(orderNumber: "12345", orderDate: new Date())  invoice.lineItems = [      new LineItem(quantity: 1, description: 'Groovy in Action (ebook)', price: 22.00),      new LineItem(quantity: 1, description: 'Programming Erlang', price: 45.00),      new LineItem(quantity: 2, description: 'iText in Action (ebook)', price: 22.00)  ]    byte[] invoicePdf = generator.pdfFor(invoice)    FileOutputStream file = new FileOutputStream("Invoice-${invoice.orderNumber}.pdf")  file.withStream {      file.write(invoicePdf)  }  println "Generated invoice $invoice.orderNumber"  

在 清單 14 中,大部分代碼用於創建 Spring ApplicationContext,創建發票並將它寫出到一個文件。使用 pdfGenerator bean 生成發票僅需一行代碼。在通常的 Spring 應用程序中,在應用程序啟動時引導一次應用程序上下文,然後,應用程序中的組件只需使用 Spring 為它們提供的依賴項。在 Spring Web 應用程序中,可以配置一個 servlet 上下文偵聽器,在應用程序啟動時引導 Spring。例如,可以定義一個 PDF 發票生成服務,如清單 15 所示:


清單 15. 使用 PDF 生成器的服務類
				  @Service  public class InvoicePdfServiceImpl implements InvoicePdfService {        @Autowired      private PdfGenerator pdfGenerator;        public byte[] generatePdf(Long invoiceId) {          Invoice invoice = getInvoiceSomehow(invoiceId);          return pdfGenerator.pdfFor(invoice);      }        // Rest of implementation...    }  

清單 15 中的 InvoicePdfServiceImpl 類剛好被實現為一個 Java 類,它依賴於 PdfGenerator。可以很方便地將它實現為 Groovy bean。可以通過任何以編譯的或用腳本編寫的 bean 配置來使用 GroovyPdfGenerator 實現,而 InvoicePdfServiceImpl 對此一無所知。因此,使用 Groovy(或任何動態語言)對應用程序代碼而言是透明的。這樣很好,因為實現了組件之間的鬆散耦合,從而使單元測試更加容易,並且可以使用最適合的實現語言。





結束語

您已經看到了配置 Groovy 語言 bean 的一些不同的方式,以及在基於 Spring 的應用程序中使用它們是多麼容易。您可以像使用 Java 類一樣使用已編譯的 Groovy 類。您還看到了配置用腳本編寫的 Groovy 對象的一些不同的方式。應該選擇的選項取決於如何在應用程序中使用 Groovy。還可以在同一個應用程序中結合使用已編譯的和用腳本編寫的 Groovy bean。實際上,如果希望的話,還可以在同一個應用程序中同時使用 Java、Groovy、JRuby 和 BeanShell bean,但我不建議這樣做。作為開發人員,必須權衡在同一應用程序中使用多種語言的優點和缺點。

作為一種語言,Groovy 比 Java 更靈活,這使它成為很有吸引力的選擇,即使僅選擇編譯 Groovy 類也是如此。Spring 可以集成用腳本編寫的動態語言 bean,這使人們更加喜歡選擇 Groovy,因為可以在用腳本編寫的 bean 中引入附加的邏輯和靈活性。例如,正如前面看到的那樣,可以根據業務邏輯添加確定應用程序啟動時應該實例化的 bean 類型的邏輯。或者,可以將用腳本編寫的對象部署到 .groovy 文件中,使 Web 應用程序的部署更加靈活。.groovy 文件位於應用程序的 CLASSPATH 中或文件系統中的某個地方,而不是打包在 WAR 文件中。

到目前為止,您看到的所有東西都為 Spring 工具箱增加了靈活性和威力。但是,Spring 動態語言支持中最引人注目的特性可能是在應用程序運行時 監視和檢測對動態語言腳本的更改,並在 Spring 應用程序上下文中自動重新裝載 更改后的 bean。第 2 部分將深入探索這個功能。包含 bean 的靜態配置在運行時不能更改,與之對比,這個功能提供了很大的靈活性。(責任編輯:A6)






[火星人 ] Groovy 使 Spring 更出色,第 1 部分: 集成的基礎知識已經有519次圍觀

http://coctec.com/docs/linux/show-post-68978.html