位于此处的示例应用:https://github.com/rushidesai1/Grails2_4_2_BeanIssue
问题:
在resources.groovy中,如果我们声明像这样的bean
beans = {
testObject(TestObject){bean ->
bean.scope = "prototype"
map = new HashMap() // or [:]
//And also if we declare any object like this
testA = new TestA()
}
}
现在如果我们DI testObject bean或者'Holders.grailsApplication.mainContext.getBean(“testObject”)',那么我们得到的bean将有单独的'map'和singelton'testA'对象。
这里testObject被声明为'prototype',即使那时'map'和'testA'都是singleton
我想知道这是一个错误还是按设计工作。这完全是反直觉的,因为我们专门做新的,所以我们期望每次都注入一个新bean。
使用单元测试用例查看我的问题的更详细版本。
先谢谢澄清!!!
答案 0 :(得分:2)
我想知道这是一个错误还是按设计工作。
是的,我认为它按设计工作。
你的testObject
bean是一个单身人士。该单例bean只有map
和testA
属性的1个副本。您所描述的行为正是我所期望的。
修改强>
我已经查看了链接项目中的应用程序,这是正在发生的事情......
在resources.groovy
你有类似的东西:
testObject(TestObject) { bean ->
bean.scope = "prototype"
mapIssue1 = ["key1FromResource.groovy": "value1FromResource.groovy"]
}
那个testObject
bean是一个原型范围的bean,因此每次检索一个bean时,都会得到一个新实例。但是,您在bean定义中对初始化Map
进行了硬编码,因此创建的bean定义具有与之关联的Map
,因此从该bean def创建的每个bean将具有相同的Map
。如果您想要一个不同的Map
实例,可以在afterPropertiesSet
或类似实例中创建它。
https://github.com/rushidesai1/Grails2_4_2_BeanIssue/blob/e9b7c9e70da5863f0716b998462eca60924ee717/test/unit/test/SpringBeansSpec.groovy的单元测试编写得不是很好。看到发生了什么依赖于在所有这些印刷品之后询问标准品。可以通过以下方式更简单地验证行为:
资源:常规
import test.TestObject
beans = {
testObject(TestObject) { bean ->
bean.scope = "prototype"
mapIssue1 = ["key1FromResource.groovy":"value1FromResource.groovy"]
}
}
SpringBeansSpec.groovy
package test
import grails.test.mixin.TestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import spock.lang.Specification
@TestMixin(GrailsUnitTestMixin)
class SpringBeansSpec extends Specification {
static loadExternalBeans = true
void 'test bean properties'() {
setup:
def testObject1 = grailsApplication.mainContext.testObject
def testObject2 = grailsApplication.mainContext.testObject
expect: 'test TestObject beans are not the same instance'
!testObject1.is(testObject2)
and: 'the TestObject beans share values defined in the bean definition'
testObject1.mapIssue1.is(testObject2.mapIssue1)
}
}
答案 1 :(得分:0)
一方面可能会让人感到困惑的是,即使你使用new,它也应该在每次获得testA bean时创建一个新的Object,另一方面它正在按预期工作。怎么样?
好的!所以答案在于Spring java Configuration。 resources.groovy
正在使用DSL,内部是配置文件。
不确定您是否知道或记住spring @Configuration注释。使用这个我们正在使POJO成为一个配置文件。 现在Spring的规则是:
new
。 Spring变得足够明智,它是一个spring配置文件,因此new并不总是意味着一个新的Object。因此,对于等效配置文件,如果我跳过testObject并且现在映射如下:
@Configuration
public class JavaConfiguration {
@Bean
public Teacher teacher(){
TestA testA = new TestA();
return teacher;
}
}
在这里,我们使用了新的TestA()。但是spring将始终返回相同的对象,直到您明确指定使用范围Prototype。 因此,在启用原型范围之后,上面的配置文件将如下所示:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class JavaConfiguration {
@Bean
@Scope(value="prototype")
public Teacher teacher(){
TestA testA = new TestA();
return teacher;
}
}
和相应的DSL将是:
testA(TestA){bean->
bean.scope='prototype'
}
希望它有所帮助!!