SpringBoot源码解析

请添加图片描述

/**
 *这个注解主要是对三个注解的封装
 *@SpringBootConfiguration 对@Configuration的派生类,目的就是为了让TestApplication像其他Configuration注解一样。被springboot容器管理,但是为什么要包装呢?其实没有为什么,一个是spring的,一个是springboot的
 *@EnableAutoConfiguration spring自动装配,该类主要作用是使用AutoConfigurationImportSelector给容器中导入一些组件,
 *然后导出系统中所有spring.factories 文件中是EnableAutoConfiguration的值加入到了容器中,来执行自动装配。主要实现selectImports方法中的getCandidateConfigurations。
 *另外,EnableAutoConfiguration 中还实现了@AutoConfigurationPackage注解,查看这个代码,会发现主要是往容器中注入@AutoConfigurationPackage所在类的包路径。
 *@ComponentScan  根据定义的扫描路径,把符合扫描规则的类装配到spring容器中
 * 
 * */
@SpringBootApplication
public class IngredientClientApplication {

   public static void main(String[] args) {
      SpringApplication.run(IngredientClientApplication.class, args);
   }
}

spring自动装配主要是执行AutoConfigurationImportSelector类的下面方法实现。如果仔细看,这个类实现DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
BeanFactoryAware, EnvironmentAware接口。仔细观察,会发现这些接口中BeanClassLoaderAware, ResourceLoaderAware,BeanFactoryAware, EnvironmentAware都有一个共同的父类Aware。而官方给的解释是

  • Marker superinterface indicating that a bean is eligible to be notified by the Spring container of a particular framework, object through a callback-style method. Actual method signature is determined by individual subinterfaces, but should typically , consist of just one void-returning method that accepts a single argument.
    翻译过来的意思就是:标记超接口,指示bean有资格通过回调样式的方法由特定框架对象的Spring容器通知。实际的方法签名由各个子接口决定,但只包含一个接受单个参数的返回void的方法。
@Override  
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
   }
   //加载"META-INF/"+ "spring-autoconfigure-metadata.properties"文件中的过滤器。
   AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
         .loadMetadata(this.beanClassLoader);
   //获取注解的属性
   AnnotationAttributes attributes = getAttributes(annotationMetadata);
   //这里主要加载的是META-INF/spring.factories文件中名称=org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,这里扫描的是所有的文件
   List<String> configurations = getCandidateConfigurations(annotationMetadata,
         attributes);
   //使用set去重configurations
   configurations = removeDuplicates(configurations);
   //返回排除规则。
   Set<String> exclusions = getExclusions(annotationMetadata, attributes);
   //校验并打印不符合自动装配规则的类
   checkExcludedClasses(configurations, exclusions);
   //移除自动装配的类
   configurations.removeAll(exclusions);
   //根据过滤规则,过滤
   configurations = filter(configurations, autoConfigurationMetadata);
   //通知自动配置导入事件,就是通知加载META-INF/spring.factories文件AutoConfigurationImportListener。
   fireAutoConfigurationImportEvents(configurations, exclusions);
   返回自动装配类
   return StringUtils.toStringArray(configurations);
}

@Configuration //表示这是一个配置类,以前编写的配置文件一样,也可以给容器中添加组件
@EnableConfigurationProperties(HttpEncodingProperties.class) //启动指定类的
ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把
HttpEncodingProperties加入到ioc容器中
@ConditionalOnWebApplication //Spring底层@Conditional注解(Spring注解版),根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效; 判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnClass(CharacterEncodingFilter.class) //判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing =true) //判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的
//即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;

首先执行SpringApplication的构造方法,创建SpringApplication的对象。在创建对象时进行了某些初始参数的设置。

/**
 * Create a new {@link SpringApplication} instance. The application context will load
 * beans from the specified primary sources (see {@link SpringApplication class-level}
 * documentation for details. The instance can be customized before calling
 * {@link #run(String...)}.
 * @param resourceLoader the resource loader to use
 * @param primarySources the primary bean sources
 * @see #run(Class, String[])
 * @see #setSources(Set)
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    //初始化资源加载器,默认是null。
   this.resourceLoader = resourceLoader;
   //主资源不能为空,一般主资源就是启动类
   Assert.notNull(primarySources, "PrimarySources must not be null");
   //初始化主资源,并使用set去重
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
   //推断应用类型,主要是根据类路径下判断是否包含SpringBootWeb依赖,如果不包含就是NONE类型,包含就是SERVLET类型
   this.webApplicationType = deduceWebApplicationType();
   //设置应用上下文初始化器,从"META-INF/spring.factories"读取ApplicationContextInitializer类的实例名称集合并去重,并进行set去重。(一共7个)
   setInitializers((Collection) getSpringFactoriesInstances(
         ApplicationContextInitializer.class));
   //设置监听器,从"META-INF/spring.factories"读取ApplicationListener类的实例名称集合并去重,并进行set去重。(一共11个)
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   //推断主入口应用类,主要是通过new RuntimeException().getStackTrace()获取当前调用栈,获取Main方法所在类,然后赋值给mainApplicationClass
   this.mainApplicationClass = deduceMainApplicationClass();
}

上文中主要用到了getSpringFactoriesInstances方法。该方法主要是从从"META-INF/spring.factories"读取传输类的值。处理流程主要有两步,第一步获取"META-INF/spring.factories"中配置的值,第二补,通过反射创建对象。

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
      Class<?>[] parameterTypes, Object... args) {
   ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
   // Use names and ensure unique to protect against duplicates
   Set<String> names = new LinkedHashSet<>(
         SpringFactoriesLoader.loadFactoryNames(type, classLoader));//主要查看该方法,该方法中,主要方式是下面loadSpringFactories方法。
   List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
         classLoader, args, names);
   AnnotationAwareOrderComparator.sort(instances);
   return instances;
}

//仔细看这个方法,他其实值执行一次,然后其他时候都在内存中读取。这个方法是获取资源目录下"META-INF/spring.factories"中的配置行,并放到缓存中。并且一次全部获取。
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
   MultiValueMap<String, String> result = cache.get(classLoader);
   if (result != null) {
      return result;
   }

   try {
       //获取资源目录下"META-INF/spring.factories"目录
      Enumeration<URL> urls = (classLoader != null ?
            classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
            ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
      result = new LinkedMultiValueMap<>();
      //加载文件
      while (urls.hasMoreElements()) {
         URL url = urls.nextElement();
         UrlResource resource = new UrlResource(url);
         Properties properties = PropertiesLoaderUtils.loadProperties(resource);
         for (Map.Entry<?, ?> entry : properties.entrySet()) {
            List<String> factoryClassNames = Arrays.asList(
                  StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
            result.addAll((String) entry.getKey(), factoryClassNames);
         }
      }
      cache.put(classLoader, result);
      return result;
   }
   catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load factories from location [" +
            FACTORIES_RESOURCE_LOCATION + "]", ex);
   }
}
//通过反射创建对象。
private <T> List<T> createSpringFactoriesInstances(Class<T> type,
      Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args,
      Set<String> names) {
   List<T> instances = new ArrayList<>(names.size());
   for (String name : names) {
      try {
         Class<?> instanceClass = ClassUtils.forName(name, classLoader);
         Assert.isAssignable(type, instanceClass);
         Constructor<?> constructor = instanceClass
               .getDeclaredConstructor(parameterTypes);
         T instance = (T) BeanUtils.instantiateClass(constructor, args);
         instances.add(instance);
      }
      catch (Throwable ex) {
         throw new IllegalArgumentException(
               "Cannot instantiate " + type + " : " + name, ex);
      }
   }
   return instances;
}

接下来,主要介绍springBoot启动运行的run方法。其主要就是初始化信息。代码如下。

/**
 * Run the Spring application, creating and refreshing a new
 * {@link ApplicationContext}.
 * @param args the application arguments (usually passed from a Java main method)
 * @return a running {@link ApplicationContext}
 */
public ConfigurableApplicationContext run(String... args) {
   //创建一个计时器,该计时器依赖于计算机的时间,会有回拨的风险。
   StopWatch stopWatch = new StopWatch();
   //启动计时器。获取计算机时间的毫秒数,该毫秒数以UTC时间表示
   stopWatch.start();
   //定义springBoot上下问context
   ConfigurableApplicationContext context = null;
   //初始化异常报告集合。
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   //该方法主要是配置 Spring Boot 应用程序的 headless 属性。headless 属性是一个 boolean 类型的属性,
   //用于指定 Spring Boot 应用程序是否在 headless 模式下运行。如果 headless 属性设置为 true,则 Spring Boot 应用程序将在没有显示器的情况下运行
   configureHeadlessProperty();
   //创建SpringApplicationRunListeners,并从"META-INF/spring.factories"中加载SpringApplicationRunListener的实现类eventPublishingRunListener。
   // 注意:这里面有几个特别容易混淆的点。SpringApplicationRunListeners 、SpringApplicationRunListener 、ApplicationListener这三个分别的作用是什么?
   //个人理解SpringApplicationRunListener就是一个ApplicationListener的代理,而SpringApplicationRunListeners又是对SpringApplicationRunListener的封装。
   //这三个类在启动过程中是联动使用的。另外eventPublishingRunListener又使用SimpleApplicationEventMulticaster实现多播。多播有两种方式,同步和异步。
   SpringApplicationRunListeners listeners = getRunListeners(args);
   //发布应用启动事件。该启动事件就会执行上述逻辑。通过SpringApplicationRunListeners的starting。
   //调用到SpringApplicationRunListener的子类eventPublishingRunListener的starting。
   //然后eventPublishingRunListener中借助SimpleApplicationEventMulticaster实现多播到ApplicationListener。
   listeners.starting();
   try {
       //主要用于是处理启动类main函数的参数, 将其封装为一个DefaultApplicationArguments对象, 为prepareEnvironment()提供参数,
       //他里面有两个变量,其中 args保存原本的命令行参数, source成员变量保存解析后的命令行参数
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(
            args);
      //根据参数准备环境变量并通知监听器
      ConfigurableEnvironment environment = prepareEnvironment(listeners,
            applicationArguments);
      //该方法主要是检查系统中有没有设置spring.beaninfo.ignore"属性,如果没有设置,就设置成true,并将"spring.beaninfo.ignore"属性设置为系统属性里面
      //设置这个的主要作用是控制Spring框架在创建bean时是否忽略bean的java.beans.BeanInfo接口,而且spring将不再使用BeanInfo创建对象。
      configureIgnoreBeanInfo(environment);
      //创建banner打印类,这里就是spring启动过程中那个图标
      Banner printedBanner = printBanner(environment);
      //根据猜测的引用类型,创建应用上下文。就是创建一个容器
      context = createApplicationContext();
      //准备异常报告器,用来支持报告关于启动的错误
      exceptionReporters = getSpringFactoriesInstances(
            SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      //准备应用上下文,将基础信息与应用上下文绑定,就是给容器Context和容器DefaultListableBeanFactory设置属性。具体解释查看prepareContext介绍。
      prepareContext(context, environment, listeners, applicationArguments,
            printedBanner);
      //刷新应用上下文
      refreshContext(context);
      //是空方法。什么都没做。应该是后续扩展使用
      afterRefresh(context, applicationArguments);
      //停止计时监控类
      stopWatch.stop();
      //输出日志记录执行主类名、时间信息
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass)
               .logStarted(getApplicationLog(), stopWatch);
      }
      //发布应用上下文启动监听事件
      listeners.started(context);
      //执行所有的Runner运行器
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, listeners);
      throw new IllegalStateException(ex);
   }

   try {
      listeners.running(context);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

下面这个方法主要是启动类run方法中执行的准备环境变量的方法。该方法主要是将配置文件封装成对象,放在environment中。

private ConfigurableEnvironment prepareEnvironment(
      SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments) {
   // Create and configure the environment
   //创建环境配置类。getOrCreateEnvironment通过获取或者新建两种方式获取配置对象。
   ConfigurableEnvironment environment = getOrCreateEnvironment();
   //将命令行参数和配置文件中的属性值设置到环境中,这里面调用了两个方法,分别将命令行参数和配置文件中的属性值设置到环境中
   configureEnvironment(environment, applicationArguments.getSourceArgs());
   //该方法主要是通知SpringApplicationRunListeners中的所有监听器,已经准备好了环境。
   //然后监听器主要做了加载application.properties以及application-${active.profile},properties文件。     
   listeners.environmentPrepared(environment);
   //把环境配置绑定到SpringApplication对象上,以便在后续的操作中使用
   bindToSpringApplication(environment);
   //判断环境类型,如果没有Web服务器,环境会转换为标准环境
   if (this.webApplicationType == WebApplicationType.NONE) {
      environment = new EnvironmentConverter(getClassLoader())
            .convertToStandardEnvironmentIfNecessary(environment);
   }
  //这个类其实是将environment环境配置中的source取出重新包装成SpringConfigurationPropertySources。
  //并用configurationProperties作为PropertySources。放到sources的第一个。具体为啥放第一。我也不知道。还没研究到那里
   ConfigurationPropertySources.attach(environment);
   return environment;
}

repareContext介绍。repareContext主要目的是给容器DefaultListableBeanFactory和context设置参数。这个里面有几个点是在做springboot后续扩展时候很关键的点。
看下面类中的信息。listeners.contextPrepared(context)

private void prepareContext(ConfigurableApplicationContext context,
      ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments, Banner printedBanner) {
   //这个主要是给上下文设置前面加载的配置文件信息。主要是提供通过容器能够获取到相关的信息
   context.setEnvironment(environment);
   //这个主要是设置当前上下文中的resourceLoader和ClassLoader,因为在启动过程中,beanNameGenerator,resourceLoader都是空,所以这里面什么都没做。
   postProcessApplicationContext(context);
   //这里主要是获取设置到容器中的配置信息(从"META-INF/spring.factories"读取ApplicationContextInitializer类),并执行其中的initialize方法。
   //在initialize方法中,主要是给上下文的BeanFactoryPostProcessor和ApplicationLisenter添加值。
   //BeanFactoryPostProcessor对容器特有的扩展, 在容器的使用过程中,执行List<BeanFactoryPostProcessor> 对应的方法,进行扩展点的执行。在这里可以对Spring做2次开发。
   applyInitializers(context);
   //表示 ApplicationContext 准备完成,执行SpringApplicationRunListeners执行contextPrepared方法对上下文可以做一定的处理。
   //这里主要执行的是EventPublishingRunListener的contextPrepared方法。但是什么都没做。应该是给以后预留的。
   listeners.contextPrepared(context);
   //记录上下文处理日志
   if (this.logStartupInfo) {
      logStartupInfo(context.getParent() == null);
      logStartupProfileInfo(context);
   }

   // Add boot specific singleton beans
   //将 springApplicationArguments 注册为单例Bean实例
   context.getBeanFactory().registerSingleton("springApplicationArguments",
         applicationArguments);
   if (printedBanner != null) {
      //将 springBootBanner注册为单例Bean实例
      context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
   }

   // Load the sources  获得启动时加载参数的资源新
   Set<Object> sources = getAllSources();
   Assert.notEmpty(sources, "Sources must not be empty");
  // 这里面主要做了两件事情,1.创建BeanDefinitionLoader类。该类中主要包含Class用AnnotatedBeanDefinitionReader处理、Resource用XmlBeanDefinitionReader处理
  //Package用ClassPathBeanDefinitionScanner处理。2.把资源类(这里只有@SpringBootApplication注解修饰的启动类)注册到BeanFactory中
   load(context, sources.toArray(new Object[0]));
   //下面这个方法主要做了
   listeners.contextLoaded(context);
}

   /**
 * Apply any relevant post processing the {@link ApplicationContext}. Subclasses can
 * apply additional processing as required.
 * @param context the application context
 */
  //beanNameGenerator和resourceLoader默认为空,没有做任何的处理。
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
   if (this.beanNameGenerator != null) {
      context.getBeanFactory().registerSingleton(
            AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
            this.beanNameGenerator);
   }
   if (this.resourceLoader != null) {
      if (context instanceof GenericApplicationContext) {
         ((GenericApplicationContext) context)
               .setResourceLoader(this.resourceLoader);
      }
      if (context instanceof DefaultResourceLoader) {
         ((DefaultResourceLoader) context)
               .setClassLoader(this.resourceLoader.getClassLoader());
      }
   }
}


/**
 * Apply any {@link ApplicationContextInitializer}s to the context before it is
 * refreshed.
 * @param context the configured ApplicationContext (not refreshed yet)
 * @see ConfigurableApplicationContext#refresh()
 */
 //
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
   for (ApplicationContextInitializer initializer : getInitializers()) {
      Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
            initializer.getClass(), ApplicationContextInitializer.class);
      Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
      initializer.initialize(context);
   }
}

/**
 * Apply any {@link ApplicationContextInitializer}s to the context before it is
 * refreshed.
 * @param context the configured ApplicationContext (not refreshed yet)
 * @see ConfigurableApplicationContext#refresh()
 */
 //主要目的是初始化容器,并把
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
   for (ApplicationContextInitializer initializer : getInitializers()) {
      Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
            initializer.getClass(), ApplicationContextInitializer.class);
      Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
      initializer.initialize(context);
   }
}
public void contextLoaded(ConfigurableApplicationContext context) {
 
    // 获取SpringApplication实例化的时候创建的10个监听器
    for (ApplicationListener<?> listener : this.application.getListeners()) {
        // 如果该监听器是ApplicationContextAware的实例,则把ApplicationContext设置到监听器中
        if (listener instanceof ApplicationContextAware) {
        ((ApplicationContextAware) listener).setApplicationContext(context);
        }
       // 把SpringApplication实例化的时候创建的10个监听器Listener注册到ApplicationContext容器中。
        context.addApplicationListener(listener);
    }
    // 广播出ApplicationPreparedEvent事件给相应的监听器执行
    this.initialMulticaster.multicastEvent(
        new ApplicationPreparedEvent(this.application, this.args, context));
    }

refreshContext(context);

refreshContext(context);

private void refreshContext(ConfigurableApplicationContext context) {
        refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
    }
/
//这个方法在AbstractApplicationContext中。是Spring中加载Bean的核心方法,主要进行类的自动装配、注册、解析、注入

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        //刷新上下文环境,初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验,这里面主要包含三个方法
        //1.initPropertySources() 这里面什么都没做,源码备注需要子类实现。这个方法主要实现上下文中占位符的替换。
        //2.getEnvironment().validateRequiredProperties();这里面主要是校验所有需要的属性
        prepareRefresh();
        // Tell the subclass to refresh the internal bean factory.
        //该实现对上下文的底层bean工厂执行实际刷新,,并为上下文生命周期的下一阶段初始化一个建一个新的DefaultListableBeanFactory对象工厂。
        //这里系统提供了两种实现方式,一种是删除后新建,一种是取出上下文中的beanFactory并返回。
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//待后续继续研究
        // Prepare the bean factory for use in this context.
        //对beanFactory的各种功能进行填充,包括设置ClassLoader、添加PostProcessor,设置编辑注册器,添加applicationContextAwareprocessor处理器等
        //扩展点:这里面applicationContextAwareprocessor的作用是啥呢。这个类用于在Bean实例化过程中进行定制化的处理。再bean实例化前。
        //会执行applicationContextAwareprocessor#postProcessBeforeInitialization(),在这个方法中,ApplicationContextAwareProcessor会检测当前处理的Bean是否实现了
        //ApplicationContextAware接口,这样Bean就可以通过调用getApplicationContext方法来获取到Spring应用上下文的引用。
        //再日常使用中,大家经常创建一个SpringContextUtils implements ApplicationContextAware就是这个类做的
        prepareBeanFactory(beanFactory);
        try {
            // Allows post-processing of the bean factory in context subclasses.
            //提前处理BeanFactory中的后置处理器。在这一步中,可以对BeanFactory进行自定义的处理,例如添加自定义的后置处理
            postProcessBeanFactory(beanFactory);
            // Invoke factory processors registered as beans in the context.
            //激活各种beanfactory处理器
            invokeBeanFactoryPostProcessors(beanFactory);
            // Register bean processors that intercept bean creation.
            //分类、排序、注册(注入)所有的BeanPostProcessors,用于处理 bean 的初始化流程
            registerBeanPostProcessors(beanFactory);
            // Initialize message source for this context.
            //初始化上下文中的资源文件如国际化文件和多语言的处理
            initMessageSource();
            // Initialize event multicaster for this context.
            //初始化上下文事件广播器,也就是注册 applicationEventMulticaster SingletonBean
            initApplicationEventMulticaster();
            // Initialize other special beans in specific context subclasses.
            //给子类扩展初始化其他bean
            onRefresh();
            // Check for listener beans and register them.
            //注册监听着
            registerListeners();
            // Instantiate all remaining (non-lazy-init) singletons.
            //初始化剩余的非懒惰的bean,即初始化非延迟加载的bean
            finishBeanFactoryInitialization(beanFactory);
            // Last step: publish corresponding event.
            //发完成刷新过程,通知声明周期处理器刷新过程,同时发出ContextRefreshEvent通知别人
            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();
        }
    }
}

//PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())解析
//该方法的主要功能就是执行BeanFactoryPostProcessors。
public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

   // Invoke BeanDefinitionRegistryPostProcessors first, if any.
   Set<String> processedBeans = new HashSet<>();

   if (beanFactory instanceof BeanDefinitionRegistry) {
      BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
      List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
      List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
      
      for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
         if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
            BeanDefinitionRegistryPostProcessor registryProcessor =
                  (BeanDefinitionRegistryPostProcessor) postProcessor;
            registryProcessor.postProcessBeanDefinitionRegistry(registry);
            registryProcessors.add(registryProcessor);
         }
         else {
            regularPostProcessors.add(postProcessor);
         }
      }

      // Do not initialize FactoryBeans here: We need to leave all regular beans
      // uninitialized to let the bean factory post-processors apply to them!
      // Separate between BeanDefinitionRegistryPostProcessors that implement
      // PriorityOrdered, Ordered, and the rest.
      List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

      // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
      String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
         if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
         }
      }
      sortPostProcessors(currentRegistryProcessors, beanFactory);
      registryProcessors.addAll(currentRegistryProcessors);
      invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
      currentRegistryProcessors.clear();

      // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
      postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      for (String ppName : postProcessorNames) {
         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();

      // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
      boolean reiterate = true;
      while (reiterate) {
         reiterate = false;
         postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
         for (String ppName : postProcessorNames) {
            if (!processedBeans.contains(ppName)) {
               currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
               processedBeans.add(ppName);
               reiterate = true;
            }
         }
         sortPostProcessors(currentRegistryProcessors, beanFactory);
         registryProcessors.addAll(currentRegistryProcessors);
         invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
         currentRegistryProcessors.clear();
      }

      // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
      invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
      invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
   }

   else {
      // Invoke factory processors registered with the context instance.
      invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
   }

   // Do not initialize FactoryBeans here: We need to leave all regular beans
   // uninitialized to let the bean factory post-processors apply to them!
   String[] postProcessorNames =
         beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

   // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
   // Ordered, and the rest.
   List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
   List<String> orderedPostProcessorNames = new ArrayList<>();
   List<String> nonOrderedPostProcessorNames = new ArrayList<>();
   for (String ppName : postProcessorNames) {
      if (processedBeans.contains(ppName)) {
         // skip - already processed in first phase above
      }
      else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
         priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
      }
      else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
         orderedPostProcessorNames.add(ppName);
      }
      else {
         nonOrderedPostProcessorNames.add(ppName);
      }
   }

   // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
   sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

   // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
   List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
   for (String postProcessorName : orderedPostProcessorNames) {
      orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   sortPostProcessors(orderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

   // Finally, invoke all other BeanFactoryPostProcessors.
   List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
   for (String postProcessorName : nonOrderedPostProcessorNames) {
      nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

   // Clear cached merged bean definitions since the post-processors might have
   // modified the original metadata, e.g. replacing placeholders in values...
   beanFactory.clearMetadataCache();
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值