老生谈spring(十八):getBean
1、preInstantiateSingletons这个方法会遍历beanNames时首先判断这个bean是不是FactoryBean,如果是则创建FactoryBean,否则直接getBean创建这个bean。这个方法在容器初始化的时候被调用,至于单例的非懒加载的bean才会被创建。
2、getBean调用了doGetBean方法,看了这么久的spring代码,想必你已经指定带do的方法才是真正干活的。(doGetBean方法稍长,将拆分成几段)
3、doGetBean方法一进来就从三级缓存中取,这个三级缓存是用来解决spring的循环依赖的,后面的章节会详细讲解。由于一开始这个bean是没有创建,所有肯定获取不到,所有第一个if条件是不成立。
4、if条件不成立就会进入else,这一段代码就是看这个容器有没有父容器,如果有则调用父容器的getBean方法创建Bean。举个例子,例如项目中引用了spring和springMVC的web容器,SpringMVC就是子容器,spring就是父容器。这个在将springMVC的时候细讲。
5、如果没有父容器,就用这个容器创建bean。创建时先检查这个bean有没有dependsOn属性,如果有则优先创建dependsOn指定的bean。
6、检查完dependsOn就判断这个bean的作用域,这里的作用域有三种:单例、多例以及自定义的作用域。不同的作用域创建bean的流程是不一样的,所有后面会分开细讲。
// 单例域
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//多例域
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//自定义作用域
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
7、结语:本节主要展示了doGetBean方法主要干的事情,下一节将围绕单例域展开spring循环依赖的讲解。