Spring-IOC XML 配置多个相同 ID 的 bean 加载分析

我们现在仍以 xml 中配置 bean 的方式来 使用 Spring ,不考虑注解和扫包

配置相同id 的bean

定义一个 beanTransactionManager

/**
 * @author maple 2018.09.10 下午10:27
 */
public class TransactionManager {
    private static int counter = 0;

    private String beanName;


    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    public TransactionManager() {
        System.out.println("===========> ===========>  TransactionManager counter :" + (++counter));
    }

    public void hello() {
        System.out.println("===========> ===========>  hello world, counter is " + counter + ", name is " + beanName);
    }
}


TransactionManager 有一个静态变量 counter 可以判断该类被实例化了几次

Spring 管理 bean

<bean id="manager" class="com.hzways.multiply.TransactionManager">
        <property name="beanName" value="master"/>
</bean>

<bean id="manager" class="com.hzways.multiply.TransactionManager">
        <property name="beanName" value="master"/>
 </bean>

照这种方式配置,spring 会直接报错,在同一个xml文件下,这样的配置是不允许的。

Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Bean name 'manager' is already used in this <beans> element
Offending resource: URL [file:/Users/maple/developer/spring-learning/maple-spring/maple-ioc/target/classes/services3.xml]

甚至 idea 都会进行提示
idea提示

然而,我们有其他办法让Spring 能够去接纳 在 xml 中 配置 多个相同 的 bean 。

使用 import 的 方式 配置相同 id 的 bean

我们可以在 service.xml 中 配置 一个 bean ,并使用 import 的形式 导入另一个 spring 的xml 配置文件

service.xml

<bean id="manager" class="com.hzways.multiply.TransactionManager">
        <property name="beanName" value="master"/>
</bean>


<import resource="classpath*:services2.xml"/>

services2.xml

<bean id="manager" class="com.hzways.multiply.TransactionManager">
        <property name="beanName" value="slave"/>
</bean>

通过这样的配置后,Spring不会报错,启动主程序。

public class Main {

    public static void main(String[] args) throws InterruptedException {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:services3.xml");
        applicationContext.start();


        TransactionManager helloWorld = applicationContext.getBean(TransactionManager.class);

        helloWorld.hello();

        Thread.sleep(Long.MAX_VALUE);

    }
}

控制台打印如下:

===========> ===========>  TransactionManager counter :1
===========> ===========>  hello world, counter is 1, name is slave

分析控制台日志发现,TransactionManager 类 只被加载了一次,而且加载的是从 service2.xml 里面定义的bean

我们调换顺序,把 import 放在 bean 定义之上,再进行测试。


    <import resource="classpath*:services3-bean.xml"/>

    <bean id="manager" class="com.hzways.multiply.TransactionManager">
        <property name="beanName" value="master"/>
    </bean>


这次程序果然打的是 master

===========> ===========>  TransactionManager counter :1
===========> ===========>  hello world, counter is 1, name is master

总结

spring不支持 直接在一个xml文件中定义两个相同id的bean,但是可以通过 import 的形式 在另外一个xml文件中定义相同 id 的bean。
如果多个xml中定义相同 的 bean id ,Spring 默认会以最后加载到的bean为准,进行加载。


posted @ 2018-09-20 14:22  枫叶maple  阅读(1137)  评论(0编辑  收藏  举报