Grails 2.4.2豆春豆注射液

时间:2016-08-25 05:49:52

标签: spring grails grails-2.4 spring-dsl spring-groovy-config

位于此处的示例应用: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。

使用单元测试用例查看我的问题的更详细版本。

先谢谢澄清!!!

2 个答案:

答案 0 :(得分:2)

  

我想知道这是一个错误还是按设计工作。

是的,我认为它按设计工作。

你的testObject bean是一个单身人士。该单例bean只有maptestA属性的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的规则是:

  1. 默认情况下,任何创建的bean都是单例,除非另有指定。
  2. 即使您在java配置文件中使用new。 Spring变得足够明智,它是一个spring配置文件,因此new并不总是意味着一个新的Object。
  3. 因此,对于等效配置文件,如果我跳过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'
    }
    

    希望它有所帮助!!