AnnotationConfigWebApplicationContext的刷新方法分析
上文简单的分析了web容器创建步骤,本文简要阐明spring启动的关键方法refresh方法
1、AnnotationConfigWebApplicationContext的继承关系图
AnnotationConfigWebApplicationContext
>>AbstractRefreshableWebApplicationContext
>>AbstractRefreshableConfigApplicationContext
>>AbstractRefreshableApplicationContext
>>AbstractApplicationContext
>>DefaultResourceLoader
...
2、refresh方法在AbstractApplicationContext类中
refresh方法采用了模板设计模式
2.1、prepareRefresh()方法做了一些什么事情呢,从注释上看是准备上下文刷新的工作。进入其方法
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
//空方法留给子类拓展
initPropertySources();
getEnvironment().validateRequiredProperties ();
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
2.1.1、validateRequiredProperties
2.2、obtainFreshBeanFactory
2.2.1、其中refreshBeanFactory是具体的刷新BeanFactory,负责这个工作在类AbstractRefreshableApplicationContext中,顾名思义这是专门用来刷新的
。
2.2.2、getBeanFactory方法同样是从此类中获取得到的Beanfactory并返回。
由此可知在getBeanFactory之前,容器已被创建,现在重点分析2.2.1中的loadBeanDefinitions方法
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
步骤0001 AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(beanFactory);
reader.setEnvironment(getEnvironment());
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(beanFactory);
scanner.setEnvironment(getEnvironment());
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
.....
步骤0002 String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class<?> clazz = getClassLoader().loadClass(configLocation);
if (logger.isInfoEnabled()) {
logger.info("Successfully resolved class for [" + configLocation + "]");
}
步骤0003 reader.register(clazz);
}
.....
}
}
}
对于 步骤0002 String[] configLocations = getConfigLocations(); 方法,会调用父类AbstractRefreshableConfigApplicationContext的方法
注意:因为是注解版本的spring环境,所以contextConfigLocation配置的是java配置类,同理可知xml版本配置的应为spring xml文件地址
对于步骤0003 reader.register(clazz);方法
首先看看reader对象的创建,在步骤0001中
new AnnotatedBeanDefinitionReader(beanFactory);
此处的beanFactory的为之前创建的bean工厂
最终调用了reader的下面代码块中的注册方法
public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
.....
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
通过 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);将配置类注入beanFactory