@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 该方法请查看文章下面的"一:prepareRefresh()方法"
prepareRefresh();
// new一个DefaultListableBeanFactory,它同时也是一个BeanDefinitionRegistry,
//然后使用ClassPathBeanDefinitionScanner和AnnotatedBeanDefinitionReader扫描,最后生成BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 本方法最重要的地方就是处理Aware接口的实现类(ApplicationContextContextAware)
// 其他地方对学习和研究源码意义不大,但是对spring初始过程很重要
// 没必要纠结这些方法,因为我已经踩过坑了,意义不大
// 添加SPEL语言的解析器
// 添加属性编辑器
// 忽略一些自动装配的接口(此处属于难点,需要你了解xml中的default-autowire,然而现在没多少人使用xml格式了),而@Autowired并不是我们说的自动装配
// 增加对AspectJ的支持
// 设置环境变量
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
一:prepareRefresh()方法
此方法最大的作用:当我们自己实现容器的时候,用来校验系统变量是否正确
当我们自己实现容器的时候,如果重写了initPropertySources();方法,那么就会体现出prepareRefresh方法的作用
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// 该方法用于子类覆盖,子类就是我们自定义的容器
initPropertySources();
// 配合上边这个init方法执行校验
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
示例需求:程序启动之后,必须要用到一个系统变量abc,如果没有abc这个变量,程序将无法正确执行,所以程序启动之前,必须校验是否存在变量abc
示例代码:
public class MysTest extends ClassPathXmlApplicationContext {
@Override
protected void initPropertySources() {
// 不只是setRequiredProperties方法,还有很多方法用来实现更多的特性
getEnvironment().setRequiredProperties("abc");
}
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new MysTest();
// 下面这个方法会报错,提示没有abc,报错信息如下
// The following properties were declared as required
// but could not be resolved: [abc]
ctx.refresh();
}
}