2013-08-19 55 views
5

簡短的問題是:每當新代碼被熱編譯並交換時,我能否強制Grails 2.2 dev服務器重新加載(重新初始化所有單例服務等)?當任何代碼重新編譯時,我可以強制grails dev服務器重新加載嗎?

讓我用一個例子來明確問題。我們假設

  1. 我有一個叫做MyService的單一作用域服務。在它的@PostConstruct函數中,它初始化一個Helper類型的新對象(並保留參考)。

  2. run-app在開發模式,測試的東西出來,然後......

  3. 我編輯Helper.groovy

的源代碼接下來會發生什麼事是:

  • Grails自動重新編譯Helper.groovy
  • Grails交換新的代碼到運行開發服務器
  • 但新的Helper代碼不是調用,因爲已經實例化的MyService對象已經有一箇舊類型的實例的句柄。

我目前的解決辦法是保持依賴圖在我的腦海,並touch或平凡修改MyService每次我改變它的依賴的一次。但我寧願強迫dev服務器完全重新加載完全新代碼交換。

因此... 是否有可能強制開發服務器重新加載,無論何時代碼更改

而一個獎金問題:當我改變域對象,只有這樣,我可以強制開發服務器,以「跟隨」這些變化是stop-appcleanrun-app手動。我是否可以在需要時自動執行此操作?

謝謝!

+0

爲您的問題找到了解決辦法,請參閱下面「我的答案」中的「CRITICAL UPDATE」。 :) – dmahapatro

回答

5

CRITICAL UPDATE

我能夠得到您正在尋找的東西。鋪設下來,分步:

需要量 -
Helper類被修改,service類應該被刷新指修改後的輔助類。

SETUP

//src/groovy 
class SampleHelper { 
    String name = 'Heisenberg' 

    def sayMyName(){ 
     "$name" 
    } 
} 

//grails-app/service 
import javax.annotation.PostConstruct 
class SampleService { 
    String cachedName 

    @PostConstruct 
    def initIt(){ 
     cachedName = new SampleHelper().sayMyName() 
    } 

    def serviceMethod() { 
     cachedName 
    } 
} 

//controller 
class SampleController { 
    def sampleService 

    def index() { 
     render sampleService.serviceMethod() 
    } 
} 

問題描述
當輔助類name更新爲Gus,類刷新,但服務類仍引用到的SampleHelper舊實例。結果,名稱仍顯示爲Heisenberg

SOLUTION

  • 觀看輔助類。
  • 刷新輔助類的服務類onChange

這可以通過在應用程序中使用Pluginator plugin來實現,該應用程序可以靈活地觀看文件並執行某些事件。

  • 安裝插件。
  • 根據grails-app/conf添加以下ApplicationPlugin.groovy。上述步驟後,接着

作爲

class ApplicationPlugin { 
    //Watch the helper class 
    def watchedResources = "file:./src/groovy/**/*.groovy" 

    //Re-Register the bean (service class) onChange of Helper Class 
    //This can be generalized more. 
    def onChange = { event -> 
     if (event.source) { 
      def beans = beans { 
       sampleService(SampleService) { bean -> 
        bean.autowire = true 
       } 
      } 
      if (event.ctx) { 
       event.ctx.registerBeanDefinition(
         "sampleService", 
         beans.getBeanDefinition("sampleService")) 
      } 
     } 
    } 
} 
  • 問題描述應該是固定的。

注意

  • 如果遵循的所有類和文物此過程可能需要大量資源。

OLD&有效的答案

我無法重新創建的Grails 2.2.0您的問題。下面是設置我(糾正我,如果我錯了,任何地方):

//src/groovy 
class MyHelper{ 
    def sayMyName(){ 
     "Heisenberg" 
    } 
} 

//service 
import javax.annotation.PostConstruct 
class MyService { 
    def myHelper 

    @PostConstruct 
    def initIt(){ 
     myHelper = new MyHelper() 
    } 

    def serviceMethod() { 
     myHelper.sayMyName() 
    } 
} 

//controller (to test) 
class MyController { 
    def myService 

    def index() { 
     render myService.serviceMethod() 
    } 
} 

步驟:

  • 運行的初始設置。(run-app
  • 命中控制器看到「海森堡」
  • 修改MyHelper.sayMyName()返回「沃爾特·白」,而不是「海森堡」
  • 再次命中控制器,並參閱「沃爾特·白」

觀察:

  • 我寧願MyHelper一個bean和使用(注),它在使用的服務類。

進入到resources.groovy如下:

beans = { 
    myHelper(com.example.MyHelper) 
} 

服務類變爲:

class MyService { 
    def myHelper 

    def serviceMethod() { 
     myHelper.sayMyName() 
    } 
} 
  • 現在,在服務類指的領域MyHelper會給一個問題,因爲豆已經在容器中實例化了

關於獎金問題:

我無法重現問題無論是在Grails的2.2.0

//domain 
class MyDomain { 
    String name 
} 

//controller action 
def add(){ 
    def myDomain = new MyDomain(name: 'Testing').save(flush: true) 
    render myDomain.properties 
} 
  • 更改域名,添加String email
  • 保存域類。
  • 修改操作在MyDomain中添加email(顯然會創建一個新行)。
  • 保存控制器。
  • 再次進行操作。
  • 查看結果。
+0

所以首先,謝謝你的一個非常徹底的迴應!以下是對您的代碼進行修改以使其中斷:在MyService中,執行以下操作: ''' String cachedName; @PostConstruct 高清initIt(){ cachedName =新MyHelper()。sayName() } ''' 我同意這是一個有點做作,但它是類似於我的方案。 – Bosh

+1

@Bosh那麼你之前提到你只是堅持幫助者的引用(不訪問任何屬性)。你現在提到的方式你永遠不能訪問最新的幫助器,因爲服務(一種清爽的spring bean)已經被創建爲單例,只有當其源改變時才刷新**。我的bucks是用於在服務類中注入幫助器,並在需要時使用'sayMyName()'。 (修改'sayMyName()'訪問它的字段)。 – dmahapatro

+0

我明確表達了關於重構的觀點! (雖然我的實際代碼不像我們在這裏討論的那麼多)。當你說「服務......」時,已經創建爲單身,只有當它的源代碼更新時才刷新「 - 這正是我的問題所在:有沒有辦法讓我強制**所有**在任何時候刷新任何代碼重新編譯? – Bosh

相關問題