思考:单例bean何时完成创建?原型Bean何时完成创建?
public class Spring {
public static void main(String[] args) {
// 1. 加载配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
// 2. 从容器中获取 bean
Student student = context.getBean("student", Student.class);
}
}
第一次调用getBean: spring在加载配置文件
时,会调用doGetBean()
,将单例bean
全部加载到单例池
中。而原型bean
会在第二次调用时创建。【创建Bean】
第二次调用getBean: 获取bean
;延迟创建原型bean
。【创建Bean、获取Bean】
创建bean,获取bean,最终的工作实现都是doGetBean()
,那么它具体做了哪些工作呢?
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
// 1. 获取beanName ==> 如果name有&,截掉之后再返回beanName。否则直接返回beanName
String beanName = this.transformedBeanName(name);
// 2. 根据 beanName 从 单例池 中获取 单例bean
Object sharedInstance = this.getSingleton(beanName);
Object beanInstance;
if (sharedInstance != null && args == null) {
beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
// 创建bean,接下来看看spring如何创建bean?
try {
// 1. 根据 beanName 获取 RootBeanDefinition (bean定义信息)
// <bean id="" class=""></bean>
RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
// 2. 检查 BeanDefinition 是否为 抽象类
this.checkMergedBeanDefinition(mbd, beanName, args);
// 3. 获取 类 依赖的其它类 <bean id="" class="" depends-on="xx"></bean>
String[] dependsOn = mbd.getDependsOn();
// 3.1 如果存在 依赖bean,必须先实例化 依赖bean
if (dependsOn != null) {
for (String dep : dependsOn) {
registerDependentBean(dep, beanName);
getBean(dep);
}
// 4.1 创建单例bean:默认 RootBeanDefinition 的 scope="singleton"
if (mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, () -> {
try {
return this.createBean(beanName, mbd, args);
} catch (BeansException ex) {
this.destroySingleton(beanName);
throw ex;
}
});
beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
// 4.2 创建原型bean: RootBeanDefinition 的 scope="prototype"
Object prototypeInstance = null;
try {
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
beanInstance = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
// 4.3 创建bean:其它scope类型,比如request、session等
}
}
// 返回 bean
return this.adaptBeanInstance(name, beanInstance, requiredType);
}
从上面代码可以看出,真正创建bean的方法是createBean
。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}