简体   繁体   English

如何在抽象类方法中访问注入的 Grails bean?

[英]How can I access injected Grails beans in an abstract class method?

I have an abstract class that implements much of the functionality inherited by a large number of concrete classes that are registered as beans.我有一个抽象类,它实现了大量注册为 bean 的具体类所继承的大部分功能。 The beans are defined with autowiring on.这些 bean 是通过自动装配定义的。 For example:例如:

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: conf/spring/resources.groovy:

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

My Problem:我的问题:

When I run the method doSomethingElse in a MyConcrete instance, everything works as expected and the myService and myBean values are filled in with the proper values by DI.当我在 MyConcrete 实例中运行 doSomethingElse 方法时,一切都按预期工作,并且 myService 和 myBean 值由 DI 填充了正确的值。 When I execute the doSomething method in a MyConcrete instance, both the myService and myBean values are null.当我在 MyConcrete 实例中执行 doSomething 方法时,myService 和 myBean 值都为空。 It appears that the DI values are not visible in the abstract method inherited by the subclass. DI 值似乎在子类继承的抽象方法中不可见。 That really sucks.这真的很糟糕。

I can manually access the values using a context holder in the method or I can pass the values from the subclass to the abstract parent class using a modified method signature that accepts those values as parameters, but these are no good solutions.我可以使用方法中的上下文持有者手动访问值,或者我可以使用接受这些值作为参数的修改方法签名将值从子类传递到抽象父类,但这些都不是好的解决方案。 It completely breaks the usefulness of abstract class implementations and requires a lot of replicated code that I don't want to have to maintain.它完全破坏了抽象类实现的用处,并且需要大量我不想维护的重复代码。

Even worse, in my specific case, the value of myBean is actually different for each concrete class, explicitly wired in the resources.groovy file, so the generic holder approach doesn't work.更糟糕的是,在我的特定情况下,每个具体类的 myBean 的值实际上是不同的,在 resources.groovy 文件中显式连接,因此通用持有者方法不起作用。

I've looked through a number of posts relating to this including Grails services in abstract class without much result in figuring out what is going on.我已经浏览了许多与此相关的帖子,包括抽象类中的 Grails 服务,但并没有弄清楚发生了什么。 The abstract bean definition seems to be about abstracting the bean definition properties and doesn't have anything to do with abstract classes and subclass inheritance.抽象 bean 定义似乎是关于抽象 bean 定义属性,与抽象类和子类继承没有任何关系。

(1) Is this a limitation in the Grails/Spring DI support? (1) 这是 Grails/Spring DI 支持的限制吗? (2) Is there something else I need to do wrt the abstract class? (2) 抽象类还有什么我需要做的吗?

You have left out some details and I have had to make some assumptions but I have created an app with something similar to what you are describing.您遗漏了一些细节,我不得不做出一些假设,但我创建了一个与您所描述的内容类似的应用程序。 The project at https://github.com/jeffbrown/abstractbeanmethods contains the following and appears to work: https://github.com/jeffbrown/abstractbeanmethods 上的项目包含以下内容并且似乎有效:

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

abstract class MyAbstract {

    MyService myService
    MyBean myBean

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

src/groovy/demo/MyConcrete.groovy src/groovy/demo/MyConcrete.groovy

package demo

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

grails-app/conf/spring/resources.groovy 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 package demo src/groovy/demo/MySpecificBeanImpl.groovy 包演示

class MySpecificBeanImpl implements MyBean {
}

src/groovy/demo/MyBean.groovy src/groovy/demo/MyBean.groovy

package demo

interface MyBean {}

grails-app/service/demo/MyService.groovy package demo 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 package demo 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
    }
}

You may find some significant difference between something there and someting that you are doing.您可能会发现那里的某事与您正在做的某事之间存在显着差异。 If you can isolate a problematic scenario in that sample app, or provide a runnable version of your code then I will be happy to straighten it out for you.如果您可以在该示例应用程序中隔离有问题的场景,或者提供可运行的代码版本,那么我很乐意为您解决问题。

I solved this problem using @Autowired annotation我使用@Autowired注释解决了这个问题

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

@Service(User)
abstract class UserService {

    @Autowired
    OrganizationService organizationService

    //...
}

Tested on Grails 3.3.5在 Grails 3.3.5 上测试

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM