Spring boot启动流程分析精简版

版本:spring boot 2.2.2

前言

spring boot 设计目的是为了简化 spring 应用初始搭建及开发过程。

优点: 可快速搭建微服务脚手架,无需再配置xml文件,内嵌servlet容器。

spring boot 在代码里直接main函数就可以启动,那到底是怎么去启动一个应用的呢?下面开始分析。

源码分析

public static void main(String[] args) {
    //启动方式
    SpringApplication.run(Application.class, args);
}
SpringApplication类:
  public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  return run(new Class<?>[] { primarySource }, args);
 }
  
  //返回应用上下文对象
  public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  return new SpringApplication(primarySources).run(args);
 }
  
  //创建一个新实例,将加载应用程序上下文
  public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  this.resourceLoader = resourceLoader;
  Assert.notNull(primarySources, "PrimarySources must not be null");
  this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //获取web应用类型,返回servlet表示要启动对应的servlet容器,如tomcat
  this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //加载ApplicationContextInitializer实现类,首次加载spring.factories文件 (spi扩展机制加载)
    //spring容器刷新之前初始化,调用实现类initialize方法
  setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //加载ApplicationListener实现类,从缓存中获取后实例化
  setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  this.mainApplicationClass = deduceMainApplicationClass();
 }

SpringApplication构造函数主要是加载应用监听类和上下文初始化类,通过查找类路径下文件解析并获取其配置的实现类

下面来看run方法函数

//
public ConfigurableApplicationContext run(String... args) {
    //记录启动运行时间
  StopWatch stopWatch = new StopWatch();
  stopWatch.start();
  ConfigurableApplicationContext context = null;
  Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
  configureHeadlessProperty();
    //一: 创建监听实现类EventPublishingRunListener
  SpringApplicationRunListeners listeners = getRunListeners(args);
  listeners.starting();
  try {
   ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      //二:准备应用环境
   ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
   configureIgnoreBeanInfo(environment);
      //创建打印类
   Banner printedBanner = printBanner(environment);
      //三:创建应用程序上下文
   context = createApplicationContext();
      //创建异常处理回调接口类
   exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
     new Class[] { ConfigurableApplicationContext.class }, context);
      //四:准备应用上下文
   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);
   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;
 }

下面分步骤来了解启动过程。

一:创建监听实现类EventPublishingRunListener

SpringApplicationRunListeners listeners = getRunListeners(args);

  //获取运行监听器
  private SpringApplicationRunListeners getRunListeners(String[] args) {
  Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
  return new SpringApplicationRunListeners(logger,
    getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
 }

 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  ClassLoader classLoader = getClassLoader();
  // Use names and ensure unique to protect against duplicates
    //类加载器加载类路径下 META-INF/spring.factories 文件中的限定类名
  Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //加载及创建实例
  List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  AnnotationAwareOrderComparator.sort(instances);
  return instances;
 }

spring.factories文件中配置的监听类:

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

listeners.starting();

EventPublishingRunListener类:

private final SimpleApplicationEventMulticaster initialMulticaster;

 public EventPublishingRunListener(SpringApplication application, String[] args) {
  this.application = application;
  this.args = args;
  this.initialMulticaster = new SimpleApplicationEventMulticaster();
  for (ApplicationListener<?> listener : application.getListeners()) {
      //加入spring.factories文件中配置的监听类
   this.initialMulticaster.addApplicationListener(listener);
  }
 }
  
 public void starting() {
    //发布应用启动事件
  this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
 }
SimpleApplicationEventMulticaster类:
  public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
  ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
  Executor executor = getTaskExecutor();
  for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
   if (executor != null) {
    executor.execute(() -> invokeListener(listener, event));
   }
   else {
    invokeListener(listener, event);
   }
  }
 }
  ...
  
  private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
      //执行监听器事件
   listener.onApplicationEvent(event);
      ...省略异常代码
  }

二:准备应用环境

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); 注: bindToSpringApplication():将环境绑定到SpringApplication类,下文2.3已说明本次环境依赖spring cloud jar包,所以配置文件加载优先级:

  • bootstrap.yml

  • application.yml 配置文件属性通过反射注入SpringApplication对象属性值。

 private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
   ApplicationArguments applicationArguments) {
  // 2.1 创建环境对象
  ConfigurableEnvironment environment = getOrCreateEnvironment();
    //2.2 对属性源和配置文件进行配置
  configureEnvironment(environment, applicationArguments.getSourceArgs());
    //将属性源支持附加到指定的环境
  ConfigurationPropertySources.attach(environment);
    //2.3 发布环境已准备事件
  listeners.environmentPrepared(environment);
    //将环境绑定到spring 应用
  bindToSpringApplication(environment);
  if (!this.isCustomEnvironment) {
   environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
     deduceEnvironmentClass());
  }
  ConfigurationPropertySources.attach(environment);
  return environment;
 }

2.1 创建环境对象

ConfigurableEnvironment environment = getOrCreateEnvironment();

StandardServletEnvironment创建对象时会加入一组属性源 属性源名称按添加顺序排序:

  • servletConfigInitParams: Servlet配置初始化参数

  • servletContextInitParams: Servlet上下文初始化参数

  • systemProperties: 系统环境

  • systemEnvironment: JVM系统属性

private ConfigurableEnvironment getOrCreateEnvironment() {
  if (this.environment != null) {
   return this.environment;
  }
  switch (this.webApplicationType) {
    //SpringApplication初始化时已被设置为servlet类型,此时创建标准servlet环境对象
  case SERVLET:
   return new StandardServletEnvironment();
  case REACTIVE:
   return new StandardReactiveWebEnvironment();
  default:
      //标准环境对象,spring cloud初始化时会创建
   return new StandardEnvironment();
  }
 }

2.2 对属性源和配置文件进行配置

configureEnvironment(environment, applicationArguments.getSourceArgs());

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
  if (this.addConversionService) {
      //创建类型转换的服务接口,添加格式化程序和转换器
   ConversionService conversionService = ApplicationConversionService.getSharedInstance();
   environment.setConversionService((ConfigurableConversionService) conversionService);
  }
    //模板方法,可重写
    //从环境对象中获取属性源进行配置,如设置命令行属性源,用于获取命令行设置的参数
  configurePropertySources(environment, args);
    //配置默认的profiles环境标识
  configureProfiles(environment, args);
 }

2.3 发布环境已准备事件

listeners.environmentPrepared(environment);

本项目用到了spring cloud的部分组件,如spring cloud config, ribbon组件等,有依赖spring-cloud-context.jar, 所以在SpringApplication初始化时会加载BootstrapApplicationListener 监听器,此监听器用于创建spring cloud应用上下文

根据事件类型获取到的监听器:

2.3.1 分析BootstrapApplicationListener监听器

BootstrapApplicationListener类:
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
  ConfigurableEnvironment environment = event.getEnvironment();
    //禁用bootstrap配置过程
  if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,
    true)) {
   return;
  }
    //不监听bootstrap上下文事件
  if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
   return;
  }
  ConfigurableApplicationContext context = null;
    //读取环境配置属性,默认bootstarp
  String configName = environment
    .resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
  for (ApplicationContextInitializer<?> initializer : event.getSpringApplication()
    .getInitializers()) {
      //ParentContextApplicationContextInitializer:设置父上下文,添加应用监听
   if (initializer instanceof ParentContextApplicationContextInitializer) {
    context = findBootstrapContext(
      (ParentContextApplicationContextInitializer) initializer,
      configName);
   }
  }
  if (context == null) {
      //重点:创建bootstrap上下文,初始化spring cloud环境对象
   context = bootstrapServiceContext(environment, event.getSpringApplication(),
     configName);
      //监听启动失败事件,用于关闭bootstartp上下文,销毁bean
   event.getSpringApplication()
     .addListeners(new CloseContextOnFailureApplicationListener(context));
  }

  apply(context, event.getSpringApplication(), environment);
 }
 private ConfigurableApplicationContext bootstrapServiceContext(
   ConfigurableEnvironment environment, final SpringApplication application,
   String configName) {
    //新建bootstrap环境对象
  StandardEnvironment bootstrapEnvironment = new StandardEnvironment();
    ......
    
    Map<String, Object> bootstrapMap = new HashMap<>();
    //添加bootstarp配置名
  bootstrapMap.put("spring.config.name", configName);
  bootstrapMap.put("spring.main.web-application-type", "none");
    
  SpringApplicationBuilder builder = new SpringApplicationBuilder()
    .profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
    .environment(bootstrapEnvironment)
    .registerShutdownHook(false).logStartupInfo(false)
        //NONE: 获取非web应用程序的上下文环境,不会启动web容器(tomcat)
    .web(WebApplicationType.NONE);
  final SpringApplication builderApplication = builder.application();
  ......
  
    //将BootstrapImportSelector类注入容器并获取BootstrapConfiguration 配置类
  builder.sources(BootstrapImportSelectorConfiguration.class);
    //创建bootstarp上下文
  final ConfigurableApplicationContext context = builder.run();
    //设置上下文id
  context.setId("bootstrap");
  //将bootstrap上下文设置为当前应用的父上下文
    addAncestorInitializer(application, context);
  bootstrapProperties.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
    //合并属性源
  mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties);
  return context;
 }

2.3.2 分析ConfigFileApplicationListener监听器

此监听器用于加载配置文件,在创建bootstrap上下文中会加载配置的bootstrap.yml文件。

builder.run()调用后会在prepareEnvironment 方法中执行环境已准备事件,获取到ConfigFileApplicationListener监听器,在onApplicationEvent方法中由于当前是环境已准备事件,调用onApplicationEnvironmentPreparedEvent方法将其自身加入环境配置的集合。

ConfigFileApplicationListener类
  //默认搜索路径
  private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";
  
  @Override
 public void onApplicationEvent(ApplicationEvent event) {
    //环境已准备事件
  if (event instanceof ApplicationEnvironmentPreparedEvent) {
   onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
  }
  if (event instanceof ApplicationPreparedEvent) {
   onApplicationPreparedEvent(event);
  }
 }

 private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
    //获取环境变量扩展类
  List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
    //自身加入集合执行
  postProcessors.add(this);
  AnnotationAwareOrderComparator.sort(postProcessors);
  for (EnvironmentPostProcessor postProcessor : postProcessors) {
   postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
  }
    
    protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
  RandomValuePropertySource.addToEnvironment(environment);
    //加载配置文件
  new Loader(environment, resourceLoader).load();
 }
 }

创建内部类Loader,初始化构造函数时通过spi方法加载不同的配置实现类。

  • YamlPropertySourceLoader:加载.yml、.yaml格式的文件

  • PropertiesPropertySourceLoader:加载.properties格式的文件

具体路径:默认搜索路径 + 配置属性名 + 文件扩展名 例子:classpath:/bootstarp.yml

private class Loader {
    ...
    
  void load() {
   FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
     (defaultProperties) -> {
      this.profiles = new LinkedList<>();
      this.processedProfiles = new LinkedList<>();
      this.activatedProfiles = false;
      this.loaded = new LinkedHashMap<>();
            //初始化默认属性值 null,default
      initializeProfiles();
      while (!this.profiles.isEmpty()) {
       Profile profile = this.profiles.poll();
       if (isDefaultProfile(profile)) {
        addProfileToEnvironment(profile.getName());
       }
              //第一次进入,profile等于空,此时是spring cloud环境属性,根据上面的搜索路径,会找到bootstrap.yml文件,读取文件中配置的spring.profiles.active属性,读到后加入profiles属性集合,移除掉default属性值。
       load(profile, this::getPositiveProfileFilter,
         addToLoaded(MutablePropertySources::addLast, false));
       this.processedProfiles.add(profile);
      }
      load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
      addLoadedPropertySources();
      applyActiveProfiles(defaultProperties);
     });
  }
    
    private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
   getSearchLocations().forEach((location) -> {
    boolean isFolder = location.endsWith("/");
    Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
    names.forEach((name) -> load(location, name, profile, filterFactory, consumer));
   });
  }
    
    private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,
    DocumentConsumer consumer) {
      ...
   Set<String> processed = new HashSet<>();
      //properties,ymal 两个文件扩展实现类
   for (PropertySourceLoader loader : this.propertySourceLoaders) {
    for (String fileExtension : loader.getFileExtensions()) {
     if (processed.add(fileExtension)) {
      loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory,
        consumer);
     }
    }
   }
  }
}

后续会详细出spring cloud上下文加载流程, spring cloud依赖组件多,篇幅有限。此处就分析到这。下面继续分析spring boot后续流程。

三:创建应用程序上下文

context = createApplicationContext();

Class.forName()初始化AnnotationConfigServletWebServerApplicationContext类,执行静态代码块,此时没有实例化该类。通过instantiateClass方法中调用newInstance方法实例化,此时会调用父类GenericApplicationContext构造函数,执行DefaultListableBeanFactory类的实例化操作。 DefaultListableBeanFactory是默认IOC容器实现类, BeanFactory是顶层容器抽象接口,为具体的容器实现类提供了基本的规范。

protected ConfigurableApplicationContext createApplicationContext() {
  Class<?> contextClass = this.applicationContextClass;
  if (contextClass == null) {
   try {
    switch (this.webApplicationType) {
    case SERVLET:
          //创建servlet web上下文,后面会启动tomcat
     contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
     break;
    case REACTIVE:
     contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
     break;
    default:
          //spring cloud创建上下文对象
     contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
    }
   }
   catch (ClassNotFoundException ex) {
    throw new IllegalStateException(
      "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
   }
  }
    //反射创建对象
  return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
 }

四:准备应用上下文

prepareContext(context, environment, listeners, applicationArguments, printedBanner);

SpringApplication类:
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
   SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    //设置上下文环境
  context.setEnvironment(environment);
    //应用后置处理,设置服务转换接口
  postProcessApplicationContext(context);
    //初始化应用上下文
  applyInitializers(context);
    //发布上下文已初始化事件
  listeners.contextPrepared(context);
  if (this.logStartupInfo) {
   logStartupInfo(context.getParent() == null);
   logStartupProfileInfo(context);
  }
  // Add boot specific singleton beans
  ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); 
    //注册单例bean
  beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
  if (printedBanner != null) {
   beanFactory.registerSingleton("springBootBanner", printedBanner);
  }
  if (beanFactory instanceof DefaultListableBeanFactory) {
      //设置是否允许同名的bean注册,默认false,重复注册抛异常  true:自动覆盖前者
      //上文有讲,如果bootstrap.yml 和 application.yml都配置了allowBeanDefinitionOverriding属性,会读取bootstrap.yml文件的值,忽略后面的文件
   ((DefaultListableBeanFactory) beanFactory)
     .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  }
  if (this.lazyInitialization) {
   context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
  }
  // Load the sources
  Set<Object> sources = getAllSources();
  Assert.notEmpty(sources, "Sources must not be empty");
    //加载启动类,注入容器
  load(context, sources.toArray(new Object[0]));
    //发布上下文加载事件
  listeners.contextLoaded(context);
 }

注:

  • bootstrap上下文加载时,配置文件 bootstrap.yml 优先于 application.yml 加载,查到属性值后不往后查找。例如 SpringApplication 对象中 allowBeanDefinitionOverriding 属性,优先会加载bootstrap.yml中配置的值。

  • Spring boot应用上下文加载时,会在 prepareContext() -> applyInitializers(context) -> AncestorInitializer.initialize(context) 代码中将bootstrap.yml属性源移除后重新添加到数组尾部,所以后面查找属性源配置application.yml优先于bootstrap.yml。例如后面的tomcat端口配置 server.port,会优先加载application.yml中配置的端口。

五:刷新应用上下文

refreshContext(context);

//AbstractApplicationContext类
public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
   // 刷新前准备工作,初始化占位符属性源及校验必须属性
   prepareRefresh();

   // 让子类刷新内部bean工厂,设置序列化id
   ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

   // 配置工厂的标准上下文特性,例如上下文的类加载器和后处理器
   prepareBeanFactory(beanFactory);

   try {
        //5.1 允许在上下文子类中对bean工厂进行后处理
    postProcessBeanFactory(beanFactory);

        // 5.2 调用在上下文中注册为 bean 的工厂处理器
    invokeBeanFactoryPostProcessors(beanFactory);

    // 5.3 注册拦截bean 创建的 bean 处理器
    registerBeanPostProcessors(beanFactory);

    // 初始化消息国际化处理
    initMessageSource();

    // 初始化事件广播器
    initApplicationEventMulticaster();

        //初始化主题源, 启动tomcat服务并初始化监听
    onRefresh();

    // 添加监听事件,发布早期监听事件
    registerListeners();

    // 5.4 完成这个上下文的bean工厂的初始化,初始化所有剩余的单例 bean
    finishBeanFactoryInitialization(beanFactory);

    // 完成此上下文刷新,发布上下文已刷新事件
    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 {
    //重置元数据缓存信息
    resetCommonCaches();
   }
  }
 }

5.1 允许在上下文子类中对bean工厂进行后处理

postProcessBeanFactory(beanFactory);

//AnnotationConfigServletWebServerApplicationContext类
  @Override
 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  super.postProcessBeanFactory(beanFactory);
  if (this.basePackages != null && this.basePackages.length > 0) {
   this.scanner.scan(this.basePackages);
  }
  if (!this.annotatedClasses.isEmpty()) {
   this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
  }
 }

后处理bean扩展接口:

  • BeanFactoryPostProcessor 容器初始化之后触发,bean实例化之前执行

  • BeanPostProcessor 针对某个具体的bean处理,对象初始化时触发,如initMethod方法前后

  //ServletWebServerApplicationContext类
 @Override
 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    //添加 BeanPostProcessor 后置处理器, 该后置处理器主要是从 ConfigurableWebApplicationContext 上下文中获取 ServletContext 和 ServletConfig 对象
  beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this));
    //ServletContextAware:返回当前的servlet上下文
    //自动注入时忽略指定依赖接口中set方法的自动装配方式
  beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    //注册web应用的scopes
  registerWebApplicationScopes();
 }

5.2 调用在上下文中注册为 bean 的工厂处理器

invokeBeanFactoryPostProcessors(beanFactory);

该方法遍历所有的beanFactoryPostProcessors, 将BeanDefinitionRegistryPostProcessor和普通BeanFactoryPostProcessor区分开,执行对应的postProcessBeanDefinitionRegistry方法和postProcessBeanFactory方法。 其中ConfigurationClassPostProcessor是一个BeanFactory的后置处理器,在这个类中,会解析@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import等注解。

如果业务需手动向spring ioc容器注入bean, 可实现BeanFactoryPostProcessor接口,重写

postProcessBeanFactory方法;

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory)方法会执行自定义bean工厂处理逻辑。

注:

  • BeanDefinitionRegistry: 主要是向注册表中注册 BeanDefinition 实例,完成注册的过程。

  • BeanDefinitionRegistryPostProcessor: 对BeanDefinition进行一些后置处理,比如完成新的BeanDefinition注册,对已有BeanDefinition进行修改等操作。

下面我们看下代码自定义的bean是怎么注册到beanFactory的:

直接看bean definition扫描器类-ClassPathBeanDefinitionScanner

//ClassPathBeanDefinitionScanner类
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
  Assert.notEmpty(basePackages, "At least one base package must be specified");
  Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
  for (String basePackage : basePackages) {
      //扫描包路径获取BeanDefinition, 默认过滤掉不包含@Component的类
   Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
   for (BeanDefinition candidate : candidates) {
      //处理@Scope注解元数据
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
    candidate.setScope(scopeMetadata.getScopeName());
        //生成beanName
    String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
    if (candidate instanceof AbstractBeanDefinition) {
     postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    }
    if (candidate instanceof AnnotatedBeanDefinition) {
     AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
    }
        // 检查beanDefinition是否冲突
    if (checkCandidate(beanName, candidate)) {
        //创建 definitionHolder
     BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
          //对 BeanDefinitionHolder 填充代理信息
     definitionHolder =
       AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
     beanDefinitions.add(definitionHolder);
          // 注册 BeanDefinition
     registerBeanDefinition(definitionHolder, this.registry);
    }
   }
  }
  return beanDefinitions;
 }

此时代码里定义的bean已注册到spring容器中,放在beanDefinitionMap中

// DefaultListableBeanFactory类
// 存放bean对象的集合
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
this.beanDefinitionMap.put(beanName, beanDefinition);

5.3 注册拦截bean 创建的 bean 处理器

registerBeanPostProcessors(beanFactory); 该方法的作用是找到所有的BeanPostProcessor,然后调用getBean实例化, 实例化后,最后放入到BeanFactory的beanPostProcessors属性中。

PostProcessorRegistrationDelegate#registerBeanPostProcessors方法会将后置处理器AutowiredAnnotationBeanPostProcessor加入bean工厂,
该后置处理器会注入依赖的属性,如果依赖没有实例化会先实例化,然后反射进行赋值。

5.4 完成这个上下文的bean工厂的初始化,初始化所有剩余的单例 bean

finishBeanFactoryInitialization(beanFactory); finishBeanFactoryInitialization方法中会执行beanFactory.preInstantiateSingletons(),来实例化所有剩余的(非延迟初始化)单例。

//DefaultListableBeanFactory
@Override
 public void preInstantiateSingletons() throws BeansException {
  if (logger.isTraceEnabled()) {
   logger.trace("Pre-instantiating singletons in " + this);
  }
  // bean definition名字集合
  List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

  for (String beanName : beanNames) {
      //合并bean
   RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
      //非抽象、单例、非懒加载bean
   if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    if (isFactoryBean(beanName)) {
     Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
     if (bean instanceof FactoryBean) {
      final FactoryBean<?> factory = (FactoryBean<?>) bean;
      boolean isEagerInit;
      if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
       isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
           ((SmartFactoryBean<?>) factory)::isEagerInit,
         getAccessControlContext());
      }
      else {
       isEagerInit = (factory instanceof SmartFactoryBean &&
         ((SmartFactoryBean<?>) factory).isEagerInit());
      }
      if (isEagerInit) {
       getBean(beanName);
      }
     }
    }
    else {
        //获取bean
     getBean(beanName);
    }
   }
  }

  省略...
 }

AbstractAutowireCapableBeanFactory#doGetBean方法格式化beanName名称,其中getSingleton(beanName) 返回已注册单例对象, 避免循环依赖,已实例化对象放入singletonObjects集合。未找到bean实例则调用 createBean -> doCreateBean方法实例化bean, 后执行populateBean方法时会注入依赖的对象,查找依赖的属性对象时先去缓存中查找,未查到,也走createBean流程。

到此spring流程比较简单的分析完了。

总结:

  1. Springboot启动创建一个SpringApplication对象,其构造方法里获取web应用类型,加载初始化器、加载监听类,然后执行run方法;

  2. run方法主要是创建监听实现类、准备应用环境(prepareEnvironment)、创建应用程序上下文(createApplicationContext)、准备应用上下文(prepareContext)、刷新应用上下文(refreshContext)、以及后续的发布事件;

  3. prepareEnvironment方法创建上下文,对属性源进行配置,将环境绑定到SpringApplication上下文;

  4. createApplicationContext方法初始化web应用上下文,实例化该对象,此时执行父类构造函数时会实例化ioc容器实现类DefaultListableBeanFactory;

  5. prepareContext方法初始化上下文环境、加载启动类、发布上下文加载事件;

  6. refreshContext方法对bean工厂后处理、注册bean实例,启动tomcat, 实例化单例bean, 发布上下文已刷新事件;

  7. 发布应用上下文运行事件,返回容器,启动类启动完成。此时虚拟机不会退出,tomcat启动时创建了非守护线程,java应用内任何非守护线程还在运行,守护线程就不会终止。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值