spring bean 别名问题

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean class="study.spring.bean.Bean" id="bean1" name="firstBean 1stBean"></bean>
    <bean class="study.spring.bean.Bean" name="bean2;secondBean"></bean>
    <bean class="study.spring.bean.Bean"></bean>
    <alias name="firstBean" alias="bean2"></alias>
</beans>

spring 中 bean 可以定义别名,但是需要唯一,现在我定义了三个bean,并且给第一个 bean 起了个别名叫做 bean2,但是 bean2 已经是第二个bean的唯一标识了,为什么这么写不会报错?现在我从容器中获取 bean2 到底获取的是第一个 bean,还是第二个 bean?

阅读 10.2k
2 个回答

首先回答第二个问题,获取的是哪个bean?

答:获取的是第一个bean

通过一个例子来说:
配置文件

<bean id="b1" class="com.wengyingjian.springframework.test.aliassamesname.Bean1" name="bean1"/>
<bean id="b2" class="com.wengyingjian.springframework.test.aliassamesname.Bean2" name="bean2"/>
<alias name="bean1" alias="bean2"/>

定义两个空的bean:Bean1,Bean2
主函数:

public static void main(String[] args) {
    BeanFactory bf=new XmlBeanFactory(new ClassPathResource("resource.xml"));
    Object o= bf.getBean("bean2");
    System.out.println(o.getClass());
}

打印结果:

class com.wengyingjian.springframework.test.aliassamesname.Bean1

再回答第一个问题,为什么没报错?

通过Debug来看,在` BeanFactory bf=new XmlBeanFactory(new ClassPathResource("resource.xml"));
之后查看一下bf对象中的aliasMap`属性。
aliasMap

说明在问题在上一步中,继续深入
DefaultBeandDefinitionDocumentReader

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        
        //"import"
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        //"alias"
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        //"bean"
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            processBeanDefinition(ele, delegate);
        }
        //"beans"
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            //与单独的配置文件并没有太大的差别,无非是递归调用beans的解析过程。
            doRegisterBeanDefinitions(ele);
        }
    }

这个方法解析的四个判断对应的就是xml配置文件中的四种默认标签,我们在此处打个断点,然后直接跳过,程序会再次回到这个断点,再次跳过。
我们都可以猜到,第一第二次走的是bean分支,第三次走的是alias分支。所以在第三次的时候进入观察为什么注册过程中没有报错
SimpleAliaRegistry

@Override
    public void registerAlias(String name, String alias) {
        Assert.hasText(name, "'name' must not be empty");
        Assert.hasText(alias, "'alias' must not be empty");
        //1.如果name==alias,那么只需将可能存在的之前的别名移除即可。默认就是本身了。
        if (alias.equals(name)) {
            this.aliasMap.remove(alias);
        }
        else {
            //2.以alias为key查看是这个别名是否已存在
            String registeredName = this.aliasMap.get(alias);
            //2.1如果这个别名已存在
            if (registeredName != null) {
                //2.1.1已存在,且与要求相同。则不动
                if (registeredName.equals(name)) {
                    // An existing alias - no need to re-register
                    return;
                }
                if (!allowAliasOverriding()) {
                    throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                            name + "': It is already registered for name '" + registeredName + "'.");
                }
            }
            //2.2如果这个别名不存在
            //检查一下别名循环引用问题,就是下图的情况
            // b<-alias---
            // |         |
            // ---alias-->a
            checkForAliasCircle(name, alias);
            //3.最后将别名放入记录
            this.aliasMap.put(alias, name);
        }
    }

这次进的是2.1分支,别名的确是已经存在的,而且not equals所以继续检查是否允许别名重写,所以这里allowAliasOverriding方法即是不报错的关键所在,这个方法默认返回值为true

所以第一个问题的答案是:spring默认允许alias重写,所以不会报错。

看你用的是resource还是autowire,一个按照类型查找一个是名称,都是存在map里

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题