我有一些Grails服务是单例Spring bean,而不是原型。
有没有办法检索通常是单例bean的原型实例(完全注入任何依赖项)?
我想将它用于测试目的,这样我就可以搞乱原型实例(可能会改变它的metaClass以模拟出来),而不会在我对实例进行任何更改并让它们泄漏后忘记清理的风险进入其他测试。
我一直在玩这个,但没有运气。我尝试过这样的事情:
def ctx = grailsApplication.mainContext
ctx.registerPrototype("foo", MyService)
然后我可以向Spring询问MyService
def myServicePrototype = ctx.getBean("foo")
它确实每次都会给出一个新实例,但是没有一个实例的属性已自动启动,所以它们都是null。我猜想有一些方法来创建一个BeanDefinition并将它提供给BeanFactory,其中包含一些我必须缺少的autowire内容。
我希望能够提出一些通用的解决方案,不会强迫我以任何方式明确地注释目标服务。
有没有办法直接向Spring applicationContext询问通常是单例的原型版本?
答案 0 :(得分:2)
想出如何使用Grails BeanBuilder创建一个临时的ApplicationContext,它将主应用程序上下文作为父项。如果对服务进行了任何不寻常的布线/弹簧配置,这将无法工作,但Grails服务通常不会这样,所以看起来像是一个很好的默认模式:
// this works in the grails console where grailsApplication is in the binding,
// need to inject in other situations
import org.springframework.context.ApplicationContext
import grails.spring.BeanBuilder
import com.example.service.MyService
def getPrototypeInstanceOf(Class clazz) {
BeanBuilder beanBuilder = new BeanBuilder(grailsApplication.mainContext)
String beanName = "prototype${clazz.name}"
beanBuilder.beans {
"$beanName"(clazz) { bean ->
bean.autowire = 'byName'
}
}
ApplicationContext applicationContext = beanBuilder.createApplicationContext()
return applicationContext.getBean(beanName)
}
def prototypeService = getPrototypeInstanceOf(MyService)
def singletonService = grailsApplication.mainContext.getBean("myService")
assert singletonService != prototypeService
assert singletonService.injectedService == prototypeService.injectedService
答案 1 :(得分:1)
如果它仅用于测试目的并且没有冲突的依赖项(例如某些bean必须只是单个),那么您可以只创建两次Spring上下文。
编辑:另一种方法可能是您为单件服务定义工厂接口并提供该工厂接口的2个实现:1仅用于单例,第二个用于具有多个实例,具体取决于您的测试情况。