http://www.javashuo.com/article/p-uvudtich-bm.htmlhtml
在前面的几篇文章中,咱们看到Environment建立、application配置文件的加载、ApplicationContext实例对象的建立、以及主类加载成为BeanDefinition。作了这么多的准备,终于到了核心的部分,也就是ioc容器的刷新。spring
这里,咱们难免要再次回顾一下SpringAplication的run方法springboot
public ConfigurableApplicationContext run(String... args) { // 声明一个Context容器 ConfigurableApplicationContext context = null; // 获取监听器 SpringApplicationRunListeners listeners = getRunListeners(args); // 调用监听器的启动 listeners.starting(); try { // 建立并配置Environment(这个过程会加载application配置文件) ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 根据应用类型建立对应的Context容器 context = createApplicationContext(); // 刷新Context容器以前的准备 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 刷新Context容器 refreshContext(context); // 刷新Context容器以后处理 afterRefresh(context, applicationArguments); // Context容器refresh完毕发布 listeners.started(context); // 触发Context容器refresh完之后的执行 callRunners(context, applicationArguments); } catch (Throwable ex) {} try { // Context启动完毕,Runner运行完毕发布 listeners.running(context); } catch (Throwable ex) {} return context; }
run方法中,prepareContext和afterRefresh之间的refreshContext方法正是ioc容器刷新的入口方法。app
可是在阅读refreshContext方法以前,咱们得先区分一下ApplicationContext和BeanFactory二者之间的关系。在以前的文章中,咱们并无把两者进行区分。好比,咱们老是说"把Bean注册到ApplicationContext容器"。post
在咱们的理解中,容器应该是一个空间的概念,用于存放事物的东西。在spring中,存放的是Bean。而BeanFactory提供了这么一个空间用于存放Bean,因此BeanFactory才是Bean所在的主要容器,而不是咱们一直说的ApplicationContext。this
既然ApplicationContext不是容器,那它又是啥呢?咱们称之为"上下文"。"上下文"的概念咱们也许不见得那么熟,可是"场景","场所"这样的概念咱们应该就比较熟悉了。好比说"拍摄场景","交易场所"等。它们的共同点都是事件发生的地方。因此ApplicationContext正是spring定义的应用程序的事件发生场所,也就是所谓的应用上下文。spa
上面,我了解了BeanFactory做为Bean容器,而ApplicationContext做为上下文。那么Bean容器和上下文之间是什么关系呢?咱们能够看一个代码片断设计
// 通用的应用上下文实现 public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { // 默认BeanFactory的实现 private final DefaultListableBeanFactory beanFactory; // 省略 }
咱们看到BeanFactory是被组合在ApplicationContext当中的,因此它们的其中一种关系就是组合关系。也就是说应用上下文中包含着Bean工厂。code
接着,咱们分别看看ApplicationContext的类图component
咱们看到ApplicationContext和BeanFactory还存在着继承关系,这意味着ApplicationContext能够对外被当作BeanFactory来使用,这也是为何咱们老是把ApplicationContext当作容器来看的主要缘由,由于对外来看二者是一体的。
结合上面的组合关系,咱们能够知道对内的话ApplicationContext的BeanFactory相关实现会由内部组合的BeanFactory的实现类来完成具体工做。
到这里,咱们基本就明白了ApplicationContext和BeanFactory之间的关系有两种:组合、继承。
后面咱们将称呼ApplicationContext为上下文,而BeanFactory为Bean容器,进行区分。
那么BeanFactory是何时被组合到ApplicationContext当中的呢?咱们先看看ApplicationContext的实现类的类图
注意!springboot默认的servlet项目的ApplicationContext实现类是AnnotationCofnigServletWebServerApplicationContext,因此咱们会以它做为实现类来看
咱们自下而上,顺着继承链找到GenericApplicationContext咱们就会看到以前出现过的代码片断
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { private final DefaultListableBeanFactory beanFactory; public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); } // 省略 }
这里,在GenericApplicationContext的构造方法当中构建了一个DefaultListableBeanFactory的实例对象。DefaultListableBeanFactory也就是BeanFactory的默认实现,那么也就是说在构造ApplicationContext实例对象的时候建立并组合了一个BeanFactory的实例。
咱们顺便也看看DefaultListableBeanFactory的继承关系吧
这个类图只保留了BeanFactory的东西,设计路线自BeanFactory到DefaultListableBeanFactory也很清晰。
下面,咱们将正式进行refreshContext方法的阅读。打开refreshContext方法
private void refreshContext(ConfigurableApplicationContext context) { refresh(context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } }
跟进refresh方法
protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }
咱们看到,这里调用的是AbstractApplicationContext的refresh方法,顺序AnnotationConfigServletWebServerApplicationContext的继承链向上能够找到AbstractApplicationContext。
咱们继续跟进AbstractApplicationContext的refresh方法,refresh方法有点长
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 刷新前准备,设置flag、时间,初始化properties等 prepareRefresh(); // 获取ApplicationContext中组合的BeanFactory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 设置类加载器,添加后置处理器等准备 prepareBeanFactory(beanFactory); try { // 供子类实现的后置处理 postProcessBeanFactory(beanFactory); // 调用Bean工厂的后置处理器 invokeBeanFactoryPostProcessors(beanFactory); // 注册Bean的后置处理器 registerBeanPostProcessors(beanFactory); // 初始化消息源 initMessageSource(); // 初始化事件广播 initApplicationEventMulticaster(); // 供之类实现的,初始化特殊的Bean onRefresh(); // 注册监听器 registerListeners(); // 实例化全部的(non-lazy-init)单例Bean finishBeanFactoryInitialization(beanFactory); // 发布刷新完毕事件 finishRefresh(); } catch (BeansException ex) { // } finally { // } } }
在上一篇文章中,咱们提到了这么一个初始化过程:
annotation或者xml中Bean的配置 --> 内存中的BeanDefinition --> Bean
也就是实际的配置,转化成内存中的配置对象,再根据配置对象转化成具体的实例对象。说白了就是从元数据到实例的一个转化过程。
为何会说起这么一个转化过程呢?由于咱们的refresh过程主要包含的就是其中的一步,也就是从annotation或者xml的Bean配置 --> 内存中的BeanDefinition的过程。这个过程的实如今调用Bean工厂的后置处理器的时候完成,也就是invokeBeanFactoryPostProcessors方法
咱们跟进invokeBeanFactoryPostProcessors方法
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // }
这里先获取了全部后置处理器,而后调用处理。再跟进PostProcessorRegistrationDelegate的invokeBeanFactoryFactoryPostProcessors方法
该方法很长,咱们删减掉大部份内容
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors ) { // if (beanFactory instanceof BeanDefinitionRegistry) { // while (reiterate) { // 调用BeanDefinition注册的后置处理器 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // } // } else { // } // }
能够看到,调用后置处理器的时候会调用到注册BeanDefinition的后置处理器。也就是从这里开始做为BeanDefinition的注册入口
跟进invokeBeanDefinitionRegistryPostProcessors
private static void invokeBeanDefinitionRegistryPostProcessors( Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry ) { for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanDefinitionRegistry(registry); } }
这里咱们须要断点一下,看看有哪些后置处理器处理BeanDefinition注册
咱们看到了ConfigurationClassPostProcessor也就是它完成BeanDefinition注册这项工做的
咱们跟进ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { // 省略 processConfigBeanDefinitions(registry); }
继续跟进,咱们看到processConfigBeanDefinitions方法挺长的,进行了大量的缩减
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); String[] candidateNames = registry.getBeanDefinitionNames(); for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { // } else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { // 默认仅有主类被添加 configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } } // // 解析被 @Configuration 注解的类 ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); // do { // 解析的核心方法 parser.parse(candidates); parser.validate(); // candidates.clear(); // } while (!candidates.isEmpty()); // }
上一篇文章中,也就是在prepareContext方法的核心逻辑里,main方法所在的主类将会被做为BeanDefinition加载到BeanFactory当中。而在这里,该主类将被做为一个配置类被解析,解析器即ConfigurationClassParser。
咱们跟进parse方法看看
public void parse(Set<BeanDefinitionHolder> configCandidates) { for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { // 主类的解析将从这里进入 parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) {} catch (Throwable ex) {} } this.deferredImportSelectorHandler.process(); }
继续跟进parse方法
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException { processConfigurationClass(new ConfigurationClass(metadata, beanName)); }
能够看到主类做为配置类的解析过程将从processConfigurationClass这里开始
到这里,ioc容器的refresh过程先作一个小结。咱们知道了上下文和Bean容器是继承关系又是组合关系。refreshContext的核心就是为了加载BeanDefinition,而加载BeanDefinition将从main方法所在的主类开始,主类做为一个配置类将由ConfigurationClassParser解析器来完成解析的职责。下一篇文章,咱们将会看到从主类中解析出BeanDefinition的主要逻辑。