Spring容器中Bean的创建

HeJin大约 6 分钟源码解析Spring源码

测试代码

<bean id="user" class="com.sanfen.entity.User">
    <property name="id" value="100"/>
    <property name="name" value="2233"/>
    <property name="age" value="27"/>
</bean>
public class SpringDemo {
    public static final Logger logger = LoggerFactory.getLogger(SpringDemo.class);

    public static void main(String[] args) {
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        User user = (User) applicationContext.getBean("user");
        logger.info("user对象: [{}]", user);
    }
}

探究目标

我们在Spring中配置好bean之后,就可以通过bean的名称或者Class获取bean对象。现在想知道,这个bean是在什么时候创建的bean是怎么创建的?

bean是在什么时候被创建的

这个比较简单,我们写的代码就几行。可以发现第一行是处理spring的配置文件,第二行是获取bean。debug调试,看是在哪一行代码创建的。

image-20221228160046316
image-20221228160046316

执行这行代码,看User有没有被创建:

image-20221228160331136
image-20221228160331136

由此,可以得出结论。

Spring中的bean是在加载配置文件的时候创建的,之后通过getBean直接获取这个创建的bean。

bean是怎么创建的

现在,我们可以进入源码,看看bean具体是怎么创建的。也不必看得很深,看到我们熟悉的代码就行了。也不用每行代码都看,关注主要的部分:bean的创建

1.进入ClassPathXmlApplicationContext。接下来是refresh()方法

我们可以通过执行这行代码之后,查看容器中有没有对应的bean。来发现具体的执行代码。通过调试,我们发现。执行完refresh()之后,User被创建了。关键代码在这里:

image-20221228161209430
image-20221228161209430

2.进入AbstractApplicationContext。这个类里面的refresh()是最关键的,几乎整个bean的生命周期的代码都在这里,我们这次只关注bean的创建。

image-20221228161557444
image-20221228161557444

进入finishBeanFactoryInitialization()方法:

image-20221228162203217
image-20221228162203217

3.进入DefaultListableBeanFactory

image-20221228162552884
image-20221228162552884

可以发现这里有个集合beanDefinitionNames,里面存储了bean的名字。接下来是实例化bean:

image-20221228163011319
image-20221228163011319

循环体内,首先会根据bean的名称获取到BeanDefinition,这个我们先看看里面有什么东西:

image-20221228163238561
image-20221228163238561

可以发现,这个BeanDefinition就是我们在Spring配置文件中配置的bean标签。这里把xml文件里面的配置转换成了BeanDefinition对象的属性。可以猜测,后面会根据这个配置对象生成bean。BeanDefinition是很重要的,它包含了bean的定义信息。不过这次我们不关注,我们主要看bean是怎么创建的。往下看:

image-20221228163535021
image-20221228163535021

因为我们是默认配置,所以没有走FactoryBean的逻辑。FactoryBean也是重点,这次也不关注。再往下看。

4.进入AbstractBeanFactory

image-20221228163735286
image-20221228163735286

doGetBean()方法:

首先获取bean的名字:

image-20221228163855759
image-20221228163855759

接下来是一堆的检查判断,走到关键代码:

image-20221228164150776
image-20221228164150776

进入createBean()方法:

image-20221228164251049
image-20221228164251049

5.进入AbstractAutowireCapableBeanFactorycreateBean()

找到关键代码:

image-20221228164517609
image-20221228164517609

进入doCreateBean()

image-20221228164700606
image-20221228164700606

接下来获取bean的类型:

image-20221228164825125
image-20221228164825125

这里我们可以得出一个结论:bean的实例化是先创建空对象,然后再填充属性。

再往下走,可以发现这里提到了循环引用:

image-20221228170235448
image-20221228170235448

接下里是填充bean的属性:

image-20221228171152443
image-20221228171152443

调用applyPropertyValues()方法:

image-20221228171511758
image-20221228171511758

深拷贝填充属性:

image-20221228171809985
image-20221228171809985

BeanWrapper设置属性:

image-20221228171942163
image-20221228171942163

属性填充完毕。会放到对应的BeanDefinition中。接下里进行bean的初始化。

image-20221228172438304
image-20221228172438304

AbstractAutowireCapableBeanFactory中。也可以发现,之前的对象属性有了值:

image-20221228172605671
image-20221228172605671

进入initializeBean()方法,通过bean名称bean对象BeanDefinition进行bean的初始化。

image-20221228172808941
image-20221228172808941

首先会填充Aware接口相关的资源:

image-20221228173041234
image-20221228173041234

接下里进行bean的初始化方法调用,而且在bean的初始化方法前后都会调用bean后置处理器。

image-20221228173409851
image-20221228173409851

由此我们可以得出结论:

bean的创建有这几个步骤:

  • 首先会创建实例,然后再填充这个实例的属性。
  • 如果实现了Aware接口,会填充对应的资源。
  • 调用bean的初始化方法,并且调用初始化方法前后都会调用bean的后置处理器。bean的初始化方法是指bean在创建之后调用的方法。比如实现 InitializingBean/DisposableBean 接口

doCreateBean()方法中,接下来继续往下走:

image-20221228174422375
image-20221228174422375

接下进行返回。

6.AbstractAutowireCapableBeanFactory中。

image-20221228174939947
image-20221228174939947

7.进入DefaultSingletonBeanRegistrygetSingleton()方法:

image-20221228175347836
image-20221228175347836

进入addSingleton()方法

image-20221228175640424
image-20221228175640424

到了这里,发现Spring把创建的单例bean放入了一个HashMap中。key是bean的名称,value是bean对象。我们是可以通过bean的名称获取到bean。到这里就明白为什么能获取到了。就是对HashMap的操作。只不过Spring在把bean对象放入Map之前,做了大量的工作。

8.返回到AbstractBeanFactory中。

image-20221228180038496
image-20221228180038496

接下来Spring还会做相关的工作来保证bean的正常使用。

9.返回到DefaultListableBeanFactory。这时,容器中已经有了bean。

image-20221228180258445
image-20221228180258445

10.返回到AbstractApplicationContext中。

image-20221228180456332
image-20221228180456332

bean的创建就完成了。

image-20221228180544412
image-20221228180544412

总结

  • bean的创建关键方法是AbstractApplicationContext中的refresh()方法。这里定义了bean的整个生命周期的代码。

    @Override
    public void refresh() throws BeansException, IllegalStateException {
       synchronized (this.startupShutdownMonitor) {
          // Prepare this context for refreshing.
          prepareRefresh();
    
          // Tell the subclass to refresh the internal bean factory.
          ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
          // Prepare the bean factory for use in this context.
          prepareBeanFactory(beanFactory);
    
          try {
             // Allows post-processing of the bean factory in context subclasses.
             postProcessBeanFactory(beanFactory);
    
             // Invoke factory processors registered as beans in the context.
             invokeBeanFactoryPostProcessors(beanFactory);
    
             // Register bean processors that intercept bean creation.
             registerBeanPostProcessors(beanFactory);
    
             // Initialize message source for this context.
             initMessageSource();
    
             // Initialize event multicaster for this context.
             initApplicationEventMulticaster();
    
             // Initialize other special beans in specific context subclasses.
             onRefresh();
    
             // Check for listener beans and register them.
             registerListeners();
    
             // Instantiate all remaining (non-lazy-init) singletons.
             finishBeanFactoryInitialization(beanFactory);
    
             // Last step: publish corresponding event.
             finishRefresh();
          }
    
          catch (BeansException ex) {
             if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                      "cancelling refresh attempt: " + ex);
             }
    
             // Destroy already created singletons to avoid dangling resources.
             destroyBeans();
    
             // Reset 'active' flag.
             cancelRefresh(ex);
    
             // Propagate exception to caller.
             throw ex;
          }
    
          finally {
             // Reset common introspection caches in Spring's core, since we
             // might not ever need metadata for singleton beans anymore...
             resetCommonCaches();
          }
       }
    }
    
  • 首先会根据spring配置文件获取到bean的定义信息,并存储到BeanDefinition对象。

  • 接下来会先判断是不是FactoryBeanFactoryBean有自己的处理逻辑。普通bean会根据beanName获取。

  • bean的实例化是先创建空对象,然后再填充属性,使用的是深拷贝填充属性。其中会涉及到循环引用。

  • Spring通过bean名称bean对象BeanDefinition进行bean的初始化。

  • 首先会填充Aware接口相关的资源。接下里进行bean的初始化方法调用,而且在bean的初始化方法前后都会调用bean后置处理器。

  • Spring最终把创建的单例bean放入了一个HashMap中。key是bean的名称,value是bean对象。我们是可以通过bean的名称获取到bean。