Spring容器中Bean的获取
测试代码
<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
打个断点:

1.进入
AbstractApplicationContext
的getBean()
方法。

这里我们可以发现,bean是从BeanFactory
获取的。换言之,bean存储于BeanFactory
对象中。
2.进入
AbstractRefreshableApplicationContext
中的getBeanFactory()
方法。

BeanFactory
里面存储了bean的许多信息,比如定义信息、bean名称、单例bean对象等等。
3.进入
AbstractBeanFactory
中的getBean()
方法。

进入doGetBean()
:
获取bean的名字。

获取单例bean对象:

beanInstance
的获取:


AbstractBeanFactory
中的getObjectForBeanInstance()
方法:


进入adaptBeanInstance()
:

往下走:

这里就获取到了bean,bean的类型是Object,使用的时候我们进行了强转。
User user = (User) applicationContext.getBean("user");
现在我们可以判断bean的获取是在这里:

进入DefaultSingletonBeanRegistry
的getSingleton()
方法:

获取bean对象:

到这里我们发现是从singletonObjects
Map集合中根据名称获取对象,这就和我们在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)
。这次进入了:

进入DefaultListableBeanFactory
的getBean()
:


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

进入resolveNamedBean()
方法:

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

进入resolveNamedBean()
方法:

进入AbstractBeanFactory
的getBean()
方法:

这时候就是根据beanName获取bean了,和上面的流程一样。
由此可以得出结论:
- 根据
beanType
获取bean首先会在容器中获取到beanType
对应的beanName
。一个beanType
可能会有多个的beanName
。如果根据beanType
和beanName
不能唯一确定一个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
。如果根据beanType
和beanName
不能唯一确定一个bean,就会报错。 - 之后就会根据获取到的
beanName
获取bean对象,然后把这个对象进行强制类型转换,类型是我们传入的Class。