在单个应用程序上下文中定义两个相同类的Bean

16
如果我定义了两个相同类的bean,且未指定任何范围。那么该类会创建多少实例?例如,在applicationContext.xml文件中。
<bean name="testBean" class="com.test.Example"/>
<bean name="myBean" class="com.test.Example"/>
3个回答

12

Spring会创建两个类型为com.test.Example的bean,并进行自动装配,装配方式基于类型、方法名(或限定符),详情请参考Spring IOC

看下这个简单测试:

使用以下类:

public static class TestBean {
    static int INT = 1;
    public int test;
    public TestBean() {
        test = INT++;
    }


}

配置xml:

<bean name="testBean" class="com.test.TestBean"/>
<bean name="myBean" class="com.test.TestBean"/>

使用Spring容器的JUnit4测试:

@Resource
TestBean testBean;

@Resource
TestBean myBean;

@Test
public void test() {

    assertNotNull(testBean);
    assertNotNull(myBean);
    assertFalse(testBean == myBean);
    assertFalse(testBean.test == myBean.test);
}

如您所见,这个测试不会失败,因为它创建了两个类型为TestBean的实例。

请看Spring文档中的这一部分:

byName
按属性名称自动装配。Spring会寻找与需要被自动装配的属性同名的bean定义。例如,如果一个bean定义被设置为按名称自动装配,并且它包含一个master属性(即它有一个setMaster(..)方法),Spring会寻找名为master的bean定义,并使用它来设置该属性。

byType
如果容器中恰好存在一个与属性类型匹配的bean,则允许自动装配该属性。如果存在多个bean,则会抛出致命异常,表明您不能对该bean使用按类型自动装配。如果没有匹配的bean,则什么也不会发生;该属性不会被设置。

constructor
类似于byType,但适用于构造函数参数。如果容器中不存在恰好一个构造函数参数类型的bean,则会引发致命错误。


在Spring容器中,每个定义只有一个单例对象。如果我们定义了bean N次,则将创建N个该类的单例对象。 - Mukesh Singh Rathaur
谢谢@Arturo,我也有同样的疑问。现在明白了。 - Mukesh Singh Rathaur

0

在这种情况下,Spring将创建两个实例。Spring容器为每个bean定义创建一个单例实例。

当您调用getContext.getBean("testBean")时,将始终为testBean bean定义提供相同的实例

当您调用getContext.getBean("myBean")时,将始终为myBean bean定义提供相同的实例。


0

是的,在这种情况下,Spring将创建两个实例。每个bean定义中,Spring容器会创建一个单例实例。 例如:

public class Test {

    @SuppressWarnings("resource")
    public static void main(String[] args) {

        ApplicationContext ac = new ClassPathXmlApplicationContext("ws.xml");
        TestBean teatBean = (TestBean) ac.getBean(TestBean.class);
        TestBean myBean1 = (TestBean) ac.getBean(TestBean.class);
        System.out.println("a : " + teatBean.test + " : "
                + teatBean.getName());
        teatBean.setName("a TEST BEAN 1");
        System.out.println("uPdate : " + teatBean.test + " : "
                + teatBean.getName());

        System.out.println("a1 : " + myBean1.test + " : " + myBean1.getName());
        myBean1.setName(" a1 TEST BEAN 10");
        System.out.println("a1 update : " + teatBean.test + " : "
                + myBean1.getName());

    }

}


    <bean class="com.spring4hibernate4.TestBean">
        <constructor-arg name="i" value="1"></constructor-arg>
        <property name="name" value="1-name"></property>
    </bean>

    <bean class="com.spring4hibernate4.TestBean">
        <constructor-arg name="i" value="10"></constructor-arg>
        <property name="name" value="10-name"></property>
    </bean>
</beans>


public class Test {

    @SuppressWarnings("resource")
    public static void main(String[] args) {

        ApplicationContext ac = new ClassPathXmlApplicationContext("ws.xml");
        TestBean teatBean = (TestBean) ac.getBean(TestBean.class);
        TestBean myBean1 = (TestBean) ac.getBean(TestBean.class);
        System.out.println("a : " + teatBean.test + " : "
                + teatBean.getName());
        teatBean.setName("a TEST BEAN 1");
        System.out.println("uPdate : " + teatBean.test + " : "
                + teatBean.getName());

        System.out.println("a1 : " + myBean1.test + " : " + myBean1.getName());
        myBean1.setName(" a1 TEST BEAN 10");
        System.out.println("a1 update : " + teatBean.test + " : "
                + myBean1.getName());

    }

}

你在说“Spring容器为每个bean定义创建一个单例实例”的陈述是正确的,但你分享的示例bean定义是不正确的。如果你定义了两个相同类的bean,没有不同的bean id或qualifiers(标识符),Spring容器将无法理解要加载哪个bean,如果你尝试通过传递类名来访问bean,你将会得到NoUniqueBeanDefinitionException异常,因为有两个符合TestBean.class的bean。 - spiderman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接