【问题标题】:How can I access injected Grails beans in an abstract class method?如何在抽象类方法中访问注入的 Grails bean?
【发布时间】:2014-09-10 20:49:15
【问题描述】:

我有一个抽象类,它实现了由注册为 bean 的大量具体类继承的大部分功能。 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/spring/resources.groovy:

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

我的问题:

当我在 MyConcrete 实例中运行方法 doSomethingElse 时,一切都按预期工作,并且 myService 和 myBean 值由 DI 填充了正确的值。当我在 MyConcrete 实例中执行 doSomething 方法时,myService 和 myBean 值都为空。似乎 DI 值在子类继承的抽象方法中不可见。真的很烂。

我可以使用方法中的上下文持有者手动访问这些值,或者我可以使用接受这些值作为参数的修改方法签名将值从子类传递到抽象父类,但这些都不是好的解决方案。它完全破坏了抽象类实现的用处,并且需要大量我不想维护的重复代码。

更糟糕的是,在我的具体情况下,myBean 的值实际上对于每个具体类都不同,在 resources.groovy 文件中显式连接,因此通用持有人方法不起作用。

我浏览了许多与此相关的帖子,包括Grails services in abstract class,但并没有弄清楚发生了什么。抽象bean定义似乎是关于抽象bean定义属性,与抽象类和子类继承没有任何关系。

(1) 这是对 Grails/Spring DI 支持的限制吗? (2) 抽象类还有什么我需要做的吗?

【问题讨论】:

  • 您是否在resources.groovy 中将抽象类定义为抽象bean?
  • 正如我上面提到的,抽象 bean 定义更像是一个 bean 属性模板,与 Groovy 类继承没有任何关系——至少文档是这么说的。我确实为了咯咯笑而尝试了它,但它并没有像我想要的那样做任何事情。根据文档的预期。
  • 这对我有用(grails 2.4.3)。对我来说没有意义的是 doSomethingElse 有效,但 doSomething 无效。如果您在 same bean 上调用这两种方法,则它使用相同的成员变量。为什么它们对于一种方法为空,而对于另一种方法为空(除非有一些副作用会清除成员)。您是否在同一个对象上调用了这两种方法?
  • 是的,这两种方法都在 MyConcrete 实例中运行。是的,从抽象基类继承的方法中的值为 null 是非常令人惊讶的。它破坏了类继承和它提供的有用的代码重用。我推测注入发生在对象生命周期的某个地方,因此注入的值仅在子类提供的方法中可见。很奇怪。不过我是在 2.3.11 中运行的,所以我会在 2.4.3 中进行一些小测试,看看是否有所不同。
  • “我推测注入发生在对象生命周期的某个地方,因此注入的值仅在子类提供的方法中可见。” - 在生命周期中实际上没有任何一点可以进行 DI 来导致此处描述的行为。必须有其他的解释。您确定您的子类中没有任何可能相关的数据隐藏吗?拥有演示问题的可运行代码将使这更容易理解。我希望原因很简单。

标签: spring grails


【解决方案1】:

您遗漏了一些细节,我不得不做出一些假设,但我创建了一个与您所描述的内容相似的应用程序。 https://github.com/jeffbrown/abstractbeanmethods 的项目包含以下内容并且似乎可以正常工作:

src/groovy/demo/MyAbstract.groovy 包演示

abstract class MyAbstract {

    MyService myService
    MyBean myBean

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

src/groovy/demo/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/groovy/demo/MySpecificBeanImpl.groovy 包演示

class MySpecificBeanImpl implements MyBean {
}

src/groovy/demo/MyBean.groovy

package demo

interface MyBean {}

grails-app/service/demo/MyService.groovy 包演示

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/controllers/demo/DemoController.groovy 包演示

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

您可能会发现那里的某事与您正在做的某事之间存在显着差异。如果您可以隔离该示例应用程序中的问题场景,或者提供代码的可运行版本,那么我很乐意为您解决问题。

【讨论】:

  • 您的假设非常合理。您提供的应用程序在我的环境中按预期运行。我提供的示例是我实际运行的示例的显着简化版本,因此它似乎与这种复杂性有关。在我的实际代码中,我在插件中注册了 bean,并在应用程序中使用了引用依赖项。我将尝试修改您的示例以模拟我拥有的更复杂的场景,看看我是否可以以这种方式重新创建它(而不是尝试削减我的应用程序代码)。感谢您抽出时间来做这件事,杰夫。
  • @SteveHole 明白了。无论哪种方式,如果您可以隔离任何方式来重现我可以看到的应用程序中的行为,我很乐意将其理顺。
  • @JeffScottBrown 这仍然是我为此类问题找到的最佳解决方案,谢谢。在过去的两年里,有没有更好的,或者更孤立的解决方案被添加到 grails 中?
【解决方案2】:

我使用@Autowired 注解解决了这个问题

import grails.gorm.services.Service
import org.springframework.beans.factory.annotation.Autowired

@Service(User)
abstract class UserService {

    @Autowired
    OrganizationService organizationService

    //...
}

在 Grails 3.3.5 上测试

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    相关资源
    最近更新 更多