Spring容器中Bean的获取

HeJin大约 4 分钟源码解析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);
    }
}

探究目标

之前我们已经大概知道了bean是什么时候创建的,而且知道了bean是怎么被创建的。最后创建的bean被保存到了一个HashMap中。现在需要知道的是:Spring容器中bean具体是怎样获取的。关键代码就是一行:

User user = (User) applicationContext.getBean("user");

Spring容器中bean的获取流程

根据beanName获取bean

打个断点:

image-20221229133708894
image-20221229133708894

1.进入AbstractApplicationContextgetBean()方法。

image-20221229133854414
image-20221229133854414

这里我们可以发现,bean是从BeanFactory获取的。换言之,bean存储于BeanFactory对象中。

2.进入AbstractRefreshableApplicationContext中的getBeanFactory()方法。

image-20221229134244730
image-20221229134244730

BeanFactory里面存储了bean的许多信息,比如定义信息、bean名称、单例bean对象等等。

3.进入AbstractBeanFactory中的getBean()方法。

image-20221229134453161
image-20221229134453161

进入doGetBean()

获取bean的名字。

image-20221229135827062
image-20221229135827062

获取单例bean对象:

image-20221229135919990
image-20221229135919990

beanInstance的获取:

image-20221229140101632
image-20221229140101632
image-20221229140213587
image-20221229140213587

AbstractBeanFactory中的getObjectForBeanInstance()方法:

image-20221229140456133
image-20221229140456133
image-20221229140633781
image-20221229140633781

进入adaptBeanInstance()

image-20221229134714631
image-20221229134714631

往下走:

image-20221229134932871
image-20221229134932871

这里就获取到了bean,bean的类型是Object,使用的时候我们进行了强转。

User user = (User) applicationContext.getBean("user");

现在我们可以判断bean的获取是在这里:

image-20221229140823717
image-20221229140823717

进入DefaultSingletonBeanRegistrygetSingleton()方法:

image-20221229141014545
image-20221229141014545

获取bean对象:

image-20221229141159969
image-20221229141159969

到这里我们发现是从singletonObjectsMap集合中根据名称获取对象,这就和我们在Spring容器中Bean的创建中的发现一致。

  • Bean创建好之后,Spring容器会把bean会放到singletonObjects集合中,key是beanName,value是bean对象。
  • 在获取bean的时候,Spring容器同样回到Map集合中获取bean对象。只不过Spring容器在获取bean的前后都做了大量的工作。

根据beanType获取bean

上面的是根据bean的名称来获取bean,接下来我们看看根据Class获取是怎么样的:

User user = applicationContext.getBean(User.class);

AbstractApplicationContext中有多个重载的getBean()方法。之前进入的是public Object getBean(String name) 。这次进入了:

image-20221229142126808
image-20221229142126808

进入DefaultListableBeanFactorygetBean()

image-20221229142315844
image-20221229142315844
image-20221229142459383
image-20221229142459383

接下来看是怎么获取的bean对象,进入resolveBean()方法:

image-20221229142738502
image-20221229142738502

进入resolveNamedBean()方法:

image-20221229143022406
image-20221229143022406

这里是根据传入的beanType先获取对应的beanName。一个beanType可能有多个beanName。这里我们只定义了一个User对象,所以只有一个。当有多个的时候,Spring需要解决具体需要哪一个,如果两个bean的类型一致,名称也一样,解决不了,就会报错。

image-20221229143234305
image-20221229143234305

进入resolveNamedBean()方法:

image-20221229143421139
image-20221229143421139

进入AbstractBeanFactorygetBean()方法:

image-20221229143527516
image-20221229143527516

这时候就是根据beanName获取bean了,和上面的流程一样。

由此可以得出结论:

  • 根据beanType获取bean首先会在容器中获取到beanType对应的beanName。一个beanType可能会有多个的beanName。如果根据beanTypebeanName不能唯一确定一个bean,就会报错。
  • 之后就会根据获取到的beanName获取bean对象,然后把这个对象进行强制转换,类型是我们传入的Class。
  • 根据beanType获取bean底层还是通过beanName获取的。

总结

  • Bean创建好之后,Spring容器会把bean会放到singletonObjects集合中,key是beanName,value是bean对象。
  • 在获取bean的时候,Spring容器同样会到Map集合中获取bean对象。只不过Spring容器在获取bean的前后都做了大量的工作。
  • 根据beanType获取bean底层还是通过beanName获取的。
  • 根据beanType获取bean首先会在容器中获取到beanType对应的beanName。一个beanType可能会有多个的beanName。如果根据beanTypebeanName不能唯一确定一个bean,就会报错。
  • 之后就会根据获取到的beanName获取bean对象,然后把这个对象进行强制类型转换,类型是我们传入的Class。