目录
测试类
一个简单的测试类
public class Test_2 {
public static void main(String[] args) {
/* 初始化启动 spring ioc 容器 */
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext-spring.xml");
/* 从 spring ioc 容器中获取一个 bean */
ProductInfoService productInfoService = (ProductInfoService) applicationContext.getBean("productInfoServiceImpl");
System.out.println("拿到的Bean为:" + productInfoService);
}
}
对于 ApplicationContext
和 ClassPathXmlApplicationContext
类图如下
getBean()
源码解读
使用开发工具进入 DEBUG
模式,进入 getBean
方法,来到 AbstractApplicationContext
抽象类中
// 打上断点调试
ProductInfoService productInfoService = (ProductInfoService) applicationContext.getBean("productInfoServiceImpl");
查看 AbstractApplicationContext
中的 getBean
方法
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
然后我们看这里的这个 getBean
方法,实际上是调用了抽象类 AbstractBeanFactory
的 doGetBean
方法
查看 AbstractBeanFactory
的 doGetBean
方法
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**
* 通过 name 获取 beanName。这里不使用 name 直接作为 beanName 有两个原因
* 1、name 可能会以 & 字符开头,表明调用者想获取 FactoryBean 本身,而非 FactoryBean
* 实现类所创建的 bean。在 BeanFactory 中,FactoryBean 的实现类和其他的 bean 存储
* 方式是一致的,即 <beanName, bean>,beanName 中是没有 & 这个字符的。所以我们需要
* 将 name 的首字符 & 移除,这样才能从缓存里取到 FactoryBean 实例。
* 2、还是别名的问题,转换需要 &beanName
*/
final String beanName = transformedBeanName(name);
Object bean;
// 先从缓存中获取,因为在容器初始化的时候或者其他地方调用过getBean,已经完成了初始化
Object sharedInstance = getSingleton(beanName);
// 如果已经初始化过,直接从缓存中获取
if (sharedInstance != null && args == null) {
// 如果beanName的实例存在于缓存中
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(bea