2014-09-10 73 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

相关问题