Спросите у Spring прототип экземпляра Singleton Bean? - PullRequest
0 голосов
/ 07 марта 2011

У меня есть несколько сервисов Grails, которые являются синглтон-бинами Spring, а не прототипами.

Есть ли способ получить экземпляр прототипа (полностью внедренный с любыми зависимостями) того, что обычно является синглтон-бином?

Мне бы хотелось, чтобы это было в целях тестирования, чтобы я мог связываться сэкземпляр прототипа (потенциально изменяющий свой метакласс для макетирования) без риска забыть очистить после любых изменений, внесенных в экземпляр, и заставить их просочиться в другие тесты.

Я играл с этимэто немного и не повезло.Я попытался сделать что-то вроде этого:

def ctx = grailsApplication.mainContext

ctx.registerPrototype("foo", MyService)

Затем я могу запросить у Spring экземпляр MyService

def myServicePrototype = ctx.getBean("foo")

, и он каждый раз дает новый экземплярвремя, но ни у одного из экземпляров не было автоматически установлено их свойства, поэтому все они нулевые.Я предполагаю, что есть какой-то способ создания BeanDefinition и подачи его в BeanFactory с включенными некоторыми компонентами автопровода, которые, я должен пропустить.

Я надеюсь найти какое-то общее решение, которое не заставляет меня явно аннотировать целевые сервисы каким-либо образом.

Есть ли способ напрямую запросить Spring applicationContext дляпрототип версии синглтона?

Ответы [ 2 ]

2 голосов
/ 07 марта 2011

Понял, как это сделать, используя 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 голос
/ 07 марта 2011

Если это только для целей тестирования и нет конфликтующих зависимостей (например, некоторые bean-компоненты, которые должны быть только синглтонами), то вы можете просто создать свой контекст Spring дважды.

РЕДАКТИРОВАТЬ: Другой подход может заключаться в том, чтовы определяете фабричный интерфейс для своего одноэлементного сервиса и предоставляете 2 реализации этого фабричного интерфейса: 1 только для одноэлементного и второй для нескольких экземпляров в зависимости от ситуации тестирования.

...