前言
今天这篇开始要讲解refreshContext方法了,是核心,一篇文章很难讲解完全,我会分为多篇文章来和大家一起学习,大家打起精神,一起撸码吧。
refreshContext 核心来了
这个方法接下来要和我们的Spring进行整合了,先来看看怎么调用到Spring的启动源码的吧。
//SpringBoot的refreshContext方法 private void refreshContext(ConfigurableApplicationContext context{ this.refresh(context); ... ... } //接下来的refresh就是我们的Spring的refresh,最重要的方法 protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext)applicationContext).refresh(); }
这个refreshContext方法本身并没有做太多的事,主要就是去调用Spring的refresh方法,整合了我们的Spring,我们接下来就会对这个方法进行详细的学习。注意看这个refresh来自于哪,是AbstractApplicationContext类,这个类我在《SpringBoot源码系列(三)》已经提到了是怎么来的了,如果忘记了可以回过头再看一下。
public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) {
//一些准备工作,如设置时间,属性等,不重要 this.prepareRefresh();
//重要方法,下面《this.obtainFreshBeanFactory 获取beanFactory》章节详细说明 刷新容器,找到之前创建的beanFactory并返回 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//设置了一堆的属性值,这个方法不进人内部了,总之就是设置了一些aware接口,一些beanPostProcessors接口等 this.prepareBeanFactory(beanFactory); try {
//不重要 如果是Spring进来的这是一个空方法,SpringBoot进来的话,里面添加了一个beanPostProcessors和一个aware方法 this.postProcessBeanFactory(beanFactory);
//非常重要的方法,下面《invokeBeanFactoryPostProcessors 自动装配》章节详细说明 做了两个事,一个是自动装配,一个是执行beanFactoryPostProcessors方法 this.invokeBeanFactoryPostProcessors(beanFactory);
//下面的几个方法会放到《SpringBoot源码系列(六)》中讲解 this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var9) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } }
this.obtainFreshBeanFactory 获取beanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//为我们之前创建的beanFactory附一个SerializationId this.refreshBeanFactory();
//找到之前创建的beanFactory,返回 ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); if (this.logger.isDebugEnabled()) { this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory); } return beanFactory; }
这段代码提到了之前创建的beanFactory,那是在哪里创建的呢,我们看看《SpringBoot源码系列(三)》,在这里我提到了beanFactory是在执行createApplicationContext方法,创建GenericApplicationContext类实例的时候创建的。
invokeBeanFactoryPostProcessors 自动装配
先贴出这段代码:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//分为两部分来看,第一部分 this.getBeanFactoryPostProcessors(见下面《代码片段 getBeanFactoryPostProcessors》章节),
//第二部分 执行invokeBeanFactoryPostProcessors方法(见下面《代码片段 invokeBeanFactoryPostProcessors》章节) PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors()); if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }
代码片段 getBeanFactoryPostProcessors
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() { return this.beanFactoryPostProcessors; }
这段代码就是返回了我们的全局的beanFactoryPostProcessors,是一个list集合,他的值从哪里来呢,我们回头看看《SpringBoot源码系列(四)》,当时说过在执行初始化器的时候会创建3个beanFactoryPostProcessors,这里读取到的就是那3个类。
接下来我们看看这三个类:

我们找到这三个类,然后看看他们实现了什么接口,经过查看,分别为(别嫌麻烦,因为这几个接口下面的《代码片段 invokeBeanFactoryPostProcessors》用到了,防止到时出现这几个接口时大家蒙,所以列出来了):
1 ConfigurationWarningsPostProcessor 实现了 BeanDefinitionRegistryPostProcessor接口;
2 CachingMetadataReaderFactoryPostProcessor 实现了 BeanDefinitionRegistryPostProcessor接口;
3 PropertySourceOrderingPostProcessor 实现了 BeanFactoryPostProcessor接口;
代码片段 invokeBeanFactoryPostProcessors
invokeBeanFactoryPostProcessors这个方法的代码非常多,有100多行,但是理解起来并不难,我会在注释中尽量写的详细些,大家一定要详细的看我写的注释,便于大家的理解。
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet(); ArrayList regularPostProcessors; ArrayList registryProcessors; int var9; ArrayList currentRegistryProcessors; String[] postProcessorNames;
//还记得我们的beanFactory是什么吗,在《SpringBoot源码系列(三)》 createApplicationContext 的时候创建的beanFactory,是一个DefaultListableBeanFactory,
// 我们现在查看下这个类的类图,发现这个类实现了BeanDefinitionRegistry接口,所以代码是会进入if的这段的 if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory; regularPostProcessors = new ArrayList(); registryProcessors = new ArrayList(); Iterator var6 = beanFactoryPostProcessors.iterator();
//遍历我们之前取到的三个beanFactoryPostProcessors while(var6.hasNext()) { BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();
//上面的《代码片段1》章节中已经说道了这三个类都实现了什么接口,现在向上翻一翻,发现有两个类实现了beanDefinitionRegistryPostProcessor接口,
// 所以遍历时,会有两个类进入if,有一个类进入else
// 走完这段之后,我们的registryProcessors集合会包含两个beanFactoryPostProcessors类,regularPostProcessors会包含一个 if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
//这行没啥用 registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } } currentRegistryProcessors = new ArrayList();
/ ** 按照BeanDefinitionRegistryPostProcessors这个类型,查找beanName
* 这个方法我就不详细讲解了,大家只需要知道执行之后,我们的postProcessorsNames[0]="org.springframework.context.annotation.internalConfigurationAnnotationProcessor"
* 感兴趣自己进去看看,这个方法的大致逻辑是:
* 调用了doGetBeanNamesForType方法,这个方法内部循环了beanDefinitionNames
* 这个doGetBeanNamesForyType方法比较长,需要判断是否是FactoryBean,如果是的话,会在beanName前面加上一个&(注意,这里我说的是FactoryBean,不是BeanFactory),我们的这个后面会说;
* 循环beanDefNames,然后调用isTypeMatch方法,从方法名称就可以看出,是验证我们类是否是BeanDefinitionRegistryPostProcessors类型,
* 经过判断,只有一个internalConfigurationAnnotationProcessor类满足,所以取出来了这个名称。
* 需要注意:这个名称不是真正的类,在我们《SpringBoot源码系列(三)》中的createApplicationContext,创建ApplicationContext时,这个名称加载进来的,对应了另外一个类名 -- ConfigurationClassPostProcessor;
*
* 细心的朋友会发现,下面的方法基本都在重复,反复调用getBeanNameForType获取类名;然后反复调用invokeBeanFactoryPostProcessors,我们跟踪代码看看都在做什么
**/ postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); String[] var16 = postProcessorNames; var9 = postProcessorNames.length; int var10; String ppName; for(var10 = 0; var10 < var9; ++var10) { ppName = var16[var10];
//ppName对应的类是ConfigurationClassPostProcessor类,这个类实现了下面的这个接口,所以会走到if里面 if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//执行之后,currentRegistryProcessors集合装载了ConfigurationClassPostProcessor类 currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory);
//registryProcessors里面之前已经有两个beanFactoryPostProcessors类了,这里又把当前的ConfigurationClassPostProcessor加进来了 registryProcessors.addAll(currentRegistryProcessors);
//重要方法 《SpringBoot源码加餐--自动装配》详细讲解。重点来了,自动装配,完成后项目中符合的类都会被加载到beanFactory中 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear();
//又一次按照BeanDefinitionRegistryPostProcessor类型,查找beanName,
//可能大家会有疑问,为什么相同的代码要被执行两次,这是因为我们上面查找beanName时还没有把所有的类信息都加载到我们的BeanFactory当中,
//经过了上面的自动装配之后会把所有的类加载进来,这里再次执行是看看有没有再次加载进来符合条件的类 postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); var16 = postProcessorNames; var9 = postProcessorNames.length;
//细心的朋友会发现,从这里向下的代码其实一直在重复上面的工作,就是在按照一个类型查询beanName,然后执行自动装配的方法,下面就不一一说明了 for(var10 = 0; var10 < var9; ++var10) { ppName = var16[var10]; if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear();
... ... invokeBeanFactoryPostProcessors((Collection)registryProcessors, (ConfigurableListableBeanFactory)beanFactory); invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory); } else { invokeBeanFactoryPostProcessors((Collection)beanFactoryPostProcessors, (ConfigurableListableBeanFactory)beanFactory); } ... ...
invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory); beanFactory.clearMetadataCache(); }
总结
refresh方法是整个启动流程的核心,这篇文章主要讲解了找到之前创建的beanFactory和自动装配前的一些准备工作,按照之前加载进来的beanFactoryPostProcessors的子类作为参数,反复调用invokeBeanDefinitionRegistryPostProcessors方法,完成自动装配。这里我们以第一次调用这个方法为例,注意我们传入方法中的两个参数,第一个是currentRegistryProcessors,这个参数当前的值是ConfigurationClassPostProcessor,第二个参数就是我们的beanFactory,这两个参数大家需要有个印象,等到下篇文章讲述自动装配原理的时候会用到。
接下来我会在《SpringBoot源码加餐--自动装配》中详细讲解自动装配的过程,在《SpringBoot源码系列(六)》及后续的文章中继续讲解bean的实例化初始化,以及调用beanPostprocessor等。
浙公网安备 33010602011771号