Bootstrap

十.BeanDefinition加载时机,bean名字相同时BeanDefinition的处理

一.BeanDefinition加载时机

bean的创建是根据BeanDefinition来的,那BeanDefinition 何时初始化的。

BeanDefinition 信息集合在 DefaultListableBeanFactory 中维护,看一下哪些方法对 BeanDefinition进行了修改,然后打断点测试。

主要是 registerBeanDefinition 方法,注册和修改bean定义。

配置类

@Configuration
public class MainConfigTiDaiBean {

    @Bean(name = "1")
    public Object a(){
        return new Object();
    }

    @Bean(name = "1")
    public Object b(){
        return new Object();
    }
}

测试类

@Test
    public void test1(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigTiDaiBean.class);

        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String bean:beanDefinitionNames){
            System.out.println(bean);
        }

        applicationContext.close();
    }

先是spring自带的一些bean 定义加载,是在容器的 AnnotationConfigApplicationContext 第一步this方法中执行的;

 

我们自定义config配置类 的bean定义加载,则是在 AnnotationConfigApplicationContext 第二步 register(annotatedClasses)执行。 会对bean定义集合增加。

那配置类中的 @Bean注释的方法呢?  是容器第三步 refresh中执行,对bean定义集合修改。

通过 BeanFactoryPostProcessors  对bean定义进行修改

 

二.同一个配置类中@Bean 中bean名字重复

配置类中两个bean name一样为1,结果只会加载第一个bean。

@Configuration
public class MainConfigTiDaiBean {

    @Bean(name = "1")
    public Object a(){
        return new Object();
    }

    @Bean(name = "1")
    public Object b(){
        return new Object();
    }
}

顺着registerBeanDefinition debug,有一步是根据 配置类中的bean方法去加载bean定义

第一个方法 a ,会加载 name为1的bean定义,把断点调试到 第二个方法 b,

其中会判断bean定义是否已经存在

 

逻辑是:拿着bean name 去已经存在的bean定义集合中寻找,如果找到了bean定义,则看旧bean定义所在的类,是否和新bean定义所在类相同,相同则返回,不再加载新的bean定义。

意思就是一个类中不能有两个相同的bean name。

三.不同配置类的bean名字重复

再加一个配置类,@bean 名字也为1,结果还是只有一个bean被创建。

结论:后加载的 重名beanDefination 会替代先加载的beanDefination。

@Configuration
public class MainConfigTiDaiBean2 {

    @Bean(name = "1")
    public Object a(){
        return new Object();
    }
}

核心在 DefaultListableBeanFactory 类的 registerBeanDefinition 方法。

通过当前的bean名字找到 已经存在的 旧bean定义。

旧bean定义如果不为空,就会用新bean定义覆盖旧bean定义。bean定义信息存放的集合是 beanDefinitionMap ,beanDefinitionNames 只是存放了名字。

所以后续加载的 重名bean 会替代先加载的bean。

会对旧的bean定义进行清除,如果旧bean定义已经产生了实例,可以清空等操作。

;