2014-09-10 75 views
1

我有一個抽象類,它實現了許多由註冊爲bean的大量具體類繼承的功能。這些bean是通過自動裝配定義的。例如:如何在抽象類方法中訪問注入的Grails bean?

abstract class MyAbstract { 

    MyService myService 
    MyBean myBean 

    def doSomething() { 
     def value = myService.something(myBean) 
    } 
} 


class MyConcrete extends MyAbstract { 
    def concreteField 

    def doSomethingElse() { 
     def value = myService.somethingElse(myBean) 
    } 
} 

的conf /春/ resources.groovy:

myConcrete(MyConcrete) { bean -> 
    bean.autowire = true 
    myBean = ref(MySpecificBeanImpl) 
} 

我的問題:

當我在MyConcrete實例中運行的方法doSomethingElse,一切按預期工作和爲myService並通過DI填寫myBean值和正確的值。當我在MyConcrete實例中執行doSomething方法時,myService和myBean值都爲空。看起來DI值在子類繼承的抽象方法中不可見。這真的很糟糕。

我可以使用方法中的上下文持有者手動訪問值,或者我可以使用將這些值作爲參數的修改方法簽名將值從子類傳遞給抽象父類,但這些都不是好的解決方案。它徹底打破了抽象類實現的有用性,並且需要大量我不想維護的複製代碼。

更糟糕的是,在我的具體情況下,myBean的值實際上是不同的,因爲每個具體類都顯式連接在resources.groovy文件中,所以通用持有方法不起作用。

我已經瀏覽了許多與此相關的帖子,包括Grails services in abstract class,但沒有太多結果來弄清楚發生了什麼。抽象bean定義似乎是關於抽象bean定義屬性,並且與抽象類和子類繼承沒有任何關係。

(1)這是對Grails/Spring DI支持的限制嗎? (2)還有什麼我需要做的抽象類嗎?

+0

您是否已經在resources.groovy中將抽象類定義爲抽象bean? – injecteer 2014-09-11 10:01:15

+0

正如我上面提到的那樣,抽象的bean定義更多的是一個bean屬性模板,並且與Groovy類的繼承沒有任何關係 - 至少這就是文檔所說的。我曾嘗試過它,但它沒有做任何我想要的東西。正如預期的那樣,根據文件。 – 2014-09-11 16:01:14

+0

這適用於我(grails 2.4.3)。對我來說沒有任何意義的是doSomethingElse可以工作,但是做不到。如果您在* same * bean上調用兩個方法,則它使用相同的成員變量。爲什麼它們對於一個方法是空的,而對另一個方法是空的(除非有一些清除成員的副作用)。你是否在同一個對象上調用了兩種方法? – 2014-09-13 08:13:45

回答

5

你已經遺漏了一些細節,我不得不做一些假設,但我已經創建了一個類似於你所描述的東西的應用程序。在https://github.com/jeffbrown/abstractbeanmethods該項目包含以下內容,似乎工作:

的src /常規/演示/ MyAbstract.groovy 包演示

abstract class MyAbstract { 

    MyService myService 
    MyBean myBean 

    def doSomething() { 
     myService.something(myBean) 
    } 
} 

的src /常規/演示/ MyConcrete.groovy

package demo 

class MyConcrete extends MyAbstract { 
    def doSomethingElse() { 
     def value = myService.somethingElse(myBean) 
    } 
} 

grails-app/conf/spring/resources.groovy

// Place your Spring DSL code here 
beans = { 
    myBeanImpl demo.MySpecificBeanImpl 

    myConcrete(demo.MyConcrete) { bean -> 
     bean.autowire = true 
     myBean = ref('myBeanImpl') 
    } 
} 

SRC /常規/演示/ MySpecificBeanImpl.groovy 包演示

class MySpecificBeanImpl implements MyBean { 
} 

SRC /常規/演示/ MyBean.groovy

package demo 

interface MyBean {} 

的grails-app /服務/演示/爲MyService。常規 包演示

class MyService { 

    def something(MyBean bean) { 
     "Bean class name is ${bean.class.name} in MyService.something() method" 
    } 
    def somethingElse(MyBean bean) { 
     "Bean class name is ${bean.class.name} in MyService.somethingElse() method" 
    } 
} 

的grails-app /控制器/演示/ DemoController.groovy 包演示

class DemoController { 
    def myConcrete 
    def index() { 
     def sb = new StringBuffer() 
     sb << myConcrete.doSomething() 
     sb << " and " 
     sb << myConcrete.doSomethingElse() 
     render sb 
    } 
} 

您可能會發現那裏的東西和成才之間存在一些差異顯著,你在做什麼。如果您可以在該示例應用程序中找出有問題的場景,或者提供可運行版本的代碼,那麼我會很樂意爲您解決這個問題。

+1

你的假設是非常合理的。您提供的應用程序在我的環境中按預期運行。我提供的這個樣本是我實際運行的一個非常簡化的版本,所以它看起來與這種複雜性有關。在我的實際代碼中,我將bean註冊到插件中,並在應用程序中引用依賴關係。我將嘗試修改您的示例以模擬我擁有的更復雜的場景,並查看是否可以以這種方式重新創建它(而不是嘗試削減我的應用程序代碼)。謝謝你花時間做這個傑夫。 – 2014-10-01 21:19:03

+1

@SteveHole瞭解。無論哪種方式,如果您可以隔離任何方式來重現應用程序中的行爲,我可以看到,我會很樂意將其解決。 – 2014-10-01 22:49:12

+1

@JeffScottBrown這仍然是我發現這種問題的最佳解決方案,謝謝。 在過去兩年中有沒有更好的或者更加獨立的解決方案被添加到Grails中? – omerkarj 2017-02-16 09:26:23

相關問題