obtainFreshBeanFactory是容器刷新的第二步,主要是刷新beanfactory,然后返回beanfactory。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory(); //模版方法,子类实现
return getBeanFactory();
}
refreshBeanFactory主要有两种实现,也就是分两种情况
(1)AbstractRefreshableApplicationContext
ClassPathXmlApplicationContext就是这种类型,如果使用XML配置文件生成容器,那么就会走下面的方法
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
//上面的英文注释大概是说执行此方法会关闭已经存在的beanfactory然后重新初始化
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) { //当前存在beanfactory
destroyBeans(); //销毁所有单例bean
closeBeanFactory(); //将beanfactory引用置为null
}
try {
//创建DefaultListableBeanFactory,如果有父容器就设置上
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//设置是否允许bean定义重写和是否允许循环引用
//子类可以重写这个方法以配置任何DefaultListableBeanFactory的设置
customizeBeanFactory(beanFactory);
//加载bean的定义信息(BeanDefinition)到beanfactory中
//这里会根据容器类型的不同而采用不同方式,但主要还是读取XML配置信息
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory; //保存新的beanfactory
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
(2)GenericApplicationContext
AnnotationConfigApplicationContext是这种类型,如果使用注解配置类生成容器,就会走下面的方法
/**
* Do nothing: We hold a single internal BeanFactory and rely on callers
* to register beans through our public methods (or the BeanFactory's).
* @see #registerBeanDefinition
*/
//上面英文注释是说,此类持有一个BeanFactory,并且依赖其他地方调用registerBeanDefinition方法注册bean的定义信息,因此在这什么都不用做
//GenericApplicationContext在构造器调用时要么传入一个DefaultListableBeanFactory,要么会new一个
@Override
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.beanFactory.setSerializationId(getId());
}
源码大体上看完,简单总结一下:
XML配置和注解配置产生的容器是不同的,主要的不同在于是否会在这一步加载BeanDefinition。XML配置的会在此时加载,而注解配置的不会。那么,注解配置的容器在何时加载BeanDefinition呢?
/**
* Create a new AnnotationConfigApplicationContext, deriving bean definitions
* from the given component classes and automatically refreshing the context.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
很显然,在容器refresh()之前就已经注册了(这里注册的是主配置类,@Bean标注的方法所对应的bean定义信息是在invokeBeanFactoryPostProcessors时被扫描进容器的)。而基于XML配置的容器在构造器中只是设置了配置文件的位置。
最后只要将beanfactory返回就可以了,容器刷新第二步完成。