从 SpringApplication.run 开始

从 SpringApplication.run 开始

image-20210729231954616

这是你的 SpringBoot ,启动,只需一键。

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

但这一键背后发生了什么?

挂着嘴边的 IOC 容器何时诞生,天天见的 @Autowired、@Service 如何实现,陪你一路的 Bean,穿林打叶, 始于何处又终于何方?

这次,从 SpringApplication.run 开始。

本文 SpringBoot Version : 2.1.15

SpringBoot

1. 要有光

SpringApplication.run下来:

public static ConfigurableApplicationContext run(Class<?> primarySource,String... args) {
    return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
    return (new SpringApplication(sources)).run(args);
}

首先是new SpringApplication(sources)构建 SpringApplication 实例,将 ServerApplication.class 存储在 this.primarySources 属性中。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    // 把 ServerApplication.class 设置为属性存储起来
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 设置应用类型
    this.webApplicationType = deduceWebApplicationType();
    // 设置初始化器,最后会调用这些初始化器
    setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class));
    // 设置监听器
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 根据堆栈,推断并设置主类
    this.mainApplicationClass = deduceMainApplicationClass();
}

2. run

有了实例,就要 run。这个方法看上去就知道做了一堆工作,一个个说。代码里已标出序号。

public ConfigurableApplicationContext run(String... args) {
    // 计时工具
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ***
    // 1:获取并启动监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 2:根据 SpringApplicationRunListeners 及参数来准备环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);
        configureIgnoreBeanInfo(environment);
        // 打字:启动 Spring Boot的时候打印在控制台上的ASCII艺术字
        Banner printedBanner = printBanner(environment);
        // 3:创建 Spring 容器
        context = createApplicationContext();
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        // 4:容器前置处理
        prepareContext(context, environment, listeners, applicationArguments,printedBanner);
        // 5:刷新容器
        refreshContext(context);
     // 6:Spring容器后置处理
        afterRefresh(context, applicationArguments);
      // 7:发出结束执行的事件
        listeners.started(context);
        // 8:执行Runners
        this.callRunners(context, applicationArguments);
        stopWatch.stop();
        // 9. 返回容器
        return context;
    }***
}
2.1. 监听器
        // 1:获取并启动监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();

首先看第一个,获取并启动监听器。会在 spring.factories 文件中寻找 SpringApplicationRunListener实现类名,反射构造实例,且持有SpringApplication的引用。再把实例放到SpringApplicationRunListeners容器来管理。

最后遍历执行listeners容器里所有SpringApplicationRunListener对象的starting方法,其实就是调用EventPublishingRunListenerstarting()启动。

这个也不是我们要谈的, 不展开了。

2.2. 环境构建
// 2:根据 SpringApplicationRunListeners 及参数来准备环境   
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);

稍微跟一下

private ConfigurableEnvironment prepareEnvironment(
        SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
    ***
    // 配置
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    // 发布环境已准备事件,这是第二次发布事件
    listeners.environmentPrepared(environment);
    ***
}

listeners.environmentPrepared(environment)发布事件,哪个监听器获取呢,有个很重要的,叫ConfigFileApplicationListener,顾名思义, 配置文件。

是的,项目中的 properties 和 yml 配置文件都是其内部类所加载。

场间休息
Banner printedBanner = printBanner(environment);

这个打印了启动时在控制台看到的 Spring Boot 艺术字。

2.3. 创建容器
// 3:创建 Spring 容器 
context = createApplicationContext();
protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            ***
        }
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

创建ApplicationContext, 容器类型根据webApplicationType判断。比如是SERVLET时,会通过反射装载对应的字节码,是AnnotationConfigServletWebServerApplicationContext

需要注意,这里的三个类型全都是继承GenericApplicationContext。记住,后面要考。

2.4. 事前准备
// 4:容器前置处理
prepareContext(context, environment, listeners, applicationArguments,printedBanner);

事前,什么事呢?这个准备包括了一个重要的操作:将启动类注入容器,为后续开启自动化配置奠定基础。

private void prepareContext(ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments, Banner printedBanner) {
    // 设置容器环境,包括各种变量
    context.setEnvironment(environment);
    // 执行容器后置处理
    postProcessApplicationContext(context);
    // 执行容器中的 ApplicationContextInitializer(包括 spring.factories 和自定义实例)
    applyInitializers(context);
   // 发送容器已经准备好的事件
    listeners.contextPrepared(context);
    // 注册启动参数bean,将容器指定的参数封装成bean,注入容器; 设置banner
    ***
    // 获取启动类指定的参数,可以是多个
    Set<Object> sources = getAllSources()
    // 加载启动类,将启动类注入容器
    load(context, sources.toArray(new Object[0]));
    // 发布容器已加载事件
    listeners.contextLoaded(context);
}

看一下getAllSources().

public Set<Object> getAllSources() {
    Set<Object> allSources = new LinkedHashSet();
    if (!CollectionUtils.isEmpty(this.primarySources)) {
        //获取primarySources属性,也就是之前存储的HelloWorldMainApplication.class
        allSources.addAll(this.primarySources);
    }
   ***
}

primarySources还记得不?在实例化SpringApplication时存了起来。也就是我们的启动类。

this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

再顺着listeners.contextLoaded(context)一路向下,来到load方法。以注解方式,将启动类 bean 信息加载到 beanDefinitionMap 中,后续该启动类将作为开启自动化配置的入口。

private int load(Class<?> source) {
    ***
    if (isComponent(source)) {
        // 以注解方式,将启动类 bean 信息存入 beanDefinitionMap
        this.annotatedReader.register(source);
        ***
    }
        ***
}
2.5. 好戏登场
 refreshContext(context);

刷新容器。就像本节标题,前面其实都是 Spring Boot 的工作, Bean 是放在 Spring 的 IOC 容器里,Spring 在哪呢?这就是了。

这调用的是org.springframework.context.support.AbstractApplicationContextrefresh

如果你在网上冲浪,搜索 Spring IOC 初始化,大抵都是从这开始的。当然,如果不用Spring Boot,用原生的 Spring、Spring Mvc ,那前面的流程就变了,这里就不说了。

SpringFramework

从前所述,Spring Boot 告一段落,来到 SpringFramework 的 refresh。

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 准备工作,记录时间、标记状态、处理配置文件中的占位符等
      prepareRefresh();
      // 1.初始化 IOC 容器
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      // 2. 设置 BeanFactory 的类加载器,添加BeanPostProcessor后置处理器
      prepareBeanFactory(beanFactory);
      try {
         // 提供子类覆盖的额外处理
         postProcessBeanFactory(beanFactory);
         // 3. 调用BeanFactory后置处理器
         invokeBeanFactoryPostProcessors(beanFactory);          
         // 注册Bean后置处理器BeanPostProcessor 的实现类
         registerBeanPostProcessors(beanFactory);
         // 初始化当前 ApplicationContext 的 MessageSource,国际化处理
         initMessageSource();
         // 初始化当前 ApplicationContext 的事件广播器
         initApplicationEventMulticaster();
         // 模板方法(钩子),供子类实现,初始化一些特殊的 Bean
         onRefresh();
         // 注册事件监听器,监听器需实现 ApplicationListener 接口。
         registerListeners();
         // 4. 初始化所有(non-lazy-init)singleton beans
         finishBeanFactoryInitialization(beanFactory);
         // 广播事件,ApplicationContext 初始化完成
         finishRefresh();
      }
      catch (BeansException ex) {
         // 销毁已经初始化的 singleton 的 Beans,以免有些 bean 会一直占用资源
         destroyBeans();
                ***
      }

      finally {
         ***
      }
   }
}

又是很多工作,但这里只重点关注部分内容。代码中也加上了序号。

1. 初始化 IOC 容器

// 1.初始化 IOC 容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

在没Spring Boot的岁月, 这一步会做很多重要工作,比如将 xml配置中的 bean配置信息,也就是Resource转成Document再转成BeanDefinition, 接着注册到 IOC 容器 BeanFactory。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        return getBeanFactory();
    }

image-20201009193833840

有两个实现类,大多数文章会告诉你,下一步是AbstractRefreshableApplicationContext

    protected final void refreshBeanFactory() throws BeansException {
        ***
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            ***
            loadBeanDefinitions(beanFactory);
        }
        ***
    }

接着会有不同的实现类,一般是 XmlWebApplicationContext, 之后解析配置等等。

image-20201009194053425

没错。在使用 Spring MVC,xml 配置时,当启动 tomcat ,一路往下,初始化 Spring 应用上下文创建的是WebApplicationContext。(详见 ContextLoaderListener 父类 ContextLoader)

最终实例化的实现类默认值在ContextLoader.properties中配置:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

所以这种说法是正确的。

不过现在是基于 SpringBoot 的注解方式。难道是从 XmlWebApplicationContext换成了图中的AnnotationConfigWebApplicationContext,那它怎么知道动态用了注解呢?

SpringBoot 版本

后退一步,回到refreshBeanFactory(),看看另一个实现类GenericApplicationContext

protected final void refreshBeanFactory() throws IllegalStateException {
        if (!this.refreshed.compareAndSet(false, true)) 
        ***
        this.beanFactory.setSerializationId(getId());
    }

这里几乎什么都没做,看起来像是没用的。但SpringBoot项目就是会走到这里,在第一部分SpringBoot.容器构建那里说过:

需要注意,这里的三个类型全都是继承GenericApplicationContext。记住,后面要考。

所以其实创建ApplicationContext时就选定了类型。这样的话,BeanDefinition在哪加载的?

2. 准备bean 容器

带着上一个问题,往下看。

// 2. 设置 BeanFactory 的类加载器,添加BeanPostProcessor后置处理器 
prepareBeanFactory(beanFactory);

如果是原始的 Spring MVC 模式,上一步把 xml 配置的 bean 注册后,这里会手动注册下特殊bean。

也会对 BeanFactory 各种功能进行填充,如常用注解 @Autowired、 @Qualifier 等,添加后置处理器。

3. BeanFactory 处理器

// 3. 调用BeanFactory后置处理器
invokeBeanFactoryPostProcessors(beanFactory);  

调用BeanFactoryPostProcessor各实现类的 postProcessBeanFactory() 回调方法。这个在SpringBoot里就有点重要了。

因为它实现了将 annotation 的 Bean 配置转化为 BeanDefinition ,以及注册。

是的,本章第 1 小结, SpringMvc 时期obtainFreshBeanFactory()的部分工作到了这里。刚才遗留的问题,在这听到了答案。

再一路到PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors, 有

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

这儿就是 BeanDefinition 的注册入口,注册 BeanDefinition 的后置处理器。

    private static void invokeBeanDefinitionRegistryPostProcessors(
            Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
        for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
            postProcessor.postProcessBeanDefinitionRegistry(registry);
        }
    }

其实现类是ConfigurationClassPostProcessor, 再往下到processConfigBeanDefinitions

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    for (String beanName : candidateNames) {
        // 默认仅有主类被添加
        configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
    }
    // 解析被 @Configuration 注解的类
    ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory,
            this.problemReporter,this.environment,this.resourceLoader,
            this.componentScanBeanNameGenerator,registry);
    do {
        // 解析的核心方法
        parser.parse(candidates);
        parser.validate();
    } 
}
解析

看这个解析的核心方法

parser.parse(candidates);
public void parse(Set<BeanDefinitionHolder> configCandidates) {
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();       
        // 主类的解析从这开始
              parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
       } 
}
protected final void parse(AnnotationMetadata metadata, String beanName) {
    processConfigurationClass(new ConfigurationClass(metadata, beanName));
}

主类被作为 BeanDefinition 加载到 BeanFactory 中,被 ConfigurationClassParser 解析器所解析。

protected void processConfigurationClass(ConfigurationClass configClass) {
    // 从 main方法所在主类开始,递归解析
    SourceClass sourceClass = asSourceClass(configClass);
    do {
        // 解析单个配置类
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
}

doProcessConfigurationClass负责解析的主要工作,会处理一个非常或者说必用的注解@ComponentScan,根据该注解信息得到扫描路径,开始扫描。

同时,对扫描出来的 Bean 又会返回个新的 sourceClass 用于继续解析。新 sourceClass 是上一个 sourceClass 的父类。所以该解析过程是个递归,主类开始,逐层向上。

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) {
// 处理 @ComponentScan 注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
                sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
            for (AnnotationAttributes componentScan : componentScans) {
                Set<BeanDefinitionHolder> scannedBeanDefinitions =
            // 处理扫描出来bean
                        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
                }}}
}

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
  ***
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}

现在,获得了扫描器和扫描路径, 调用doScan.

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        // 1. 扫描获取 BeanDefinition
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {
            ***
           // 2. 注册 BeanDefinition 到 BeanFactory
           registerBeanDefinition(definitionHolder, this.registry);  
        }
    }
    return beanDefinitions;
}
扫描

findCandidateComponents 方法将会根据扫描路径获取非常重要的 BeanDefinition

关于BeanDefinition,随口一提 : 在容器本身内,bean 定义表示为 BeanDefinition 对象。

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
        ***
            return scanCandidateComponents(basePackage);
    }

好了,现在路径知道了,也开始扫描了,但哪个可爱的 Class 有幸被转化为 BeanDefinition 呢?

是的,肯定有一个判断。

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        for (Resource resource : resources) {
            if (resource.isReadable()) {
                    // 类的元数据
                  MetadataReader metadataReader = this.metadataReaderFactory.
                        getMetadataReader(resource);
                  // 判断是否满足条件
                  if (isCandidateComponent(metadataReader)) { 
                            ***
}
protected boolean isCandidateComponent(MetadataReader metadataReader) {
        for (TypeFilter tf : this.excludeFilters) {    
            if (tf.match(metadataReader, getMetadataReaderFactory())) {    
                return false;
            }
        }
        for (TypeFilter tf : this.includeFilters) {
            if (tf.match(metadataReader, getMetadataReaderFactory())) {   
                return isConditionMatch(metadataReader);
            }
        }
        return false;
    }

在判断方法isCandidateComponent里,会进行很多的过滤检查处理。

其中ClassPathScanningCandidateComponentProvider#registerDefaultFilters方法,会给includeFilters添加默认的AnnotationTypeFilter负责处理 @Component,@ManagedBean等注解

最终的调用链是: AnnotationTypeFilter#match -> matchSelf.

protected boolean matchSelf(MetadataReader metadataReader) {
    AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();    
    return metadata.hasAnnotation(this.annotationType.getName()) ||    
            (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName())); 
}

这里会获取 Class 的注解元数据,检查是否有对应 annotationType, 简单来说,就是检查有没有那些我们常用的 @Service@Repository了,并检查嵌套注解是否有对应的 annotationType。

注册

回到doScan,扫描出来的 BeanDefinition 将会调用 registerBeanDefinition 注册。

protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}

public static void registerBeanDefinition(
        BeanDefinitionHolder definitionHolder,BeanDefinitionRegistry registry)  {
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    ***
}

这里的 registry,默认实现类是 DefaultListableBeanFactory 。

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

public void registerBeanDefinition(String beanName,BeanDefinition beanDefinition)  {
    ***
    if (hasBeanCreationStarted()) {
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            ***           }
        } ***
    }
}

最终,也就是将 BeanDefinition 添加到一个 key-value 的集合当中,这样就完成了注册工作。

4. 实例化Bean

前面我们得到了充满 BeanDefinition 的 BeanFactory,中间一些流程先忽略。来到最重要的地方,实例化 Bean。

// 4. 初始化所有(non-lazy-init)singleton beans
finishBeanFactoryInitialization(beanFactory);
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    ***
            beanFactory.setConversionService(
                    beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    *** 
  }

getBean, 该方法的实现位于AbstractBeanFactory.doGetBean

protected <T> T doGetBean(
        final String name,
        @Nullable final Class<T> requiredType,
        @Nullable final Object[] args,
        boolean typeCheckOnly) throws BeansException {
    final String beanName = transformedBeanName(name);
    Object bean;
    // 获取已注册的单例 Bean
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        // 根据 name 和 beanName 判断应该返回 factoryBean 还是 bean
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    } else {
        // *** 判断循环依赖、类型检查、获取父 BeanFactory
        ***
        try {
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            // 初始化依赖的Bean(@DependsOn)
            ***
            // 创建单例
            if (mbd.isSingleton()) {
                // 回调创建
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        // 创建 Bean
                        return createBean(beanName, mbd, args);
                    } 
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            } else if (mbd.isPrototype()) {
                // 如果是 prototype scope 的
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    // 创建Bean
                    prototypeInstance = createBean(beanName, mbd, args);
                } ***
            } else {
                // 既不是单例Bean,也不是prototype,获取其 Scope,委托给相应的实现类来处理
            }
        } ***
    }
    // 类型检查
    return (T) bean;
}
循环依赖
    // 尝试获取Bean
    Object sharedInstance = getSingleton(beanName);

根据 beanName 尝试从 singletonObjects 缓存中获取单例Bean,获取不到则再尝试从earlySingletonObjects、singletonFactories 从获取。同时这也是Spring 解决循环依赖的关键。

创建Bean
createBean(beanName, mbd, args);

缓存中获取不到,就创建,

Object beanInstance = doCreateBean(beanName, mbdToUse, args);

它会调用doCreateBean()。在这停顿,打这开始,又是一个热门问题:Spring Bean 生命周期

Spring Bean 生命周期

image-20201010103637056

如图,谈到 Bean 生命周期,大概都是这张图的内容。对应的其实就是上文的doCreateBean

protected Object doCreateBean(
        final String beanName, final RootBeanDefinition mbd,
        final @Nullable Object[] args) throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    ***
    if (instanceWrapper == null) {
        // 1. 说明不是 FactoryBean,实例化 Bean
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // *** 解决循环依赖等
    ***
    Object exposedObject = bean;
    try {
        // 2. 前面实例化后,属性装配,自动注入
        populateBean(beanName, mbd, instanceWrapper);
        // 3. 初始化。init-method、InitializingBean、BeanPostProcessor等,各种回调
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    } ***
    try {
        // 4. 销毁-注册回调接口
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    return exposedObject;
}

这个方法也有点长,而且每个分支跟下去都更长,这里截取部分且不进行过多深究。前面图中看着挺多,但实际可以分为几大步,代码中已标识。

1. 实例化

 instanceWrapper = createBeanInstance(beanName, mbd, args);
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
   ***
   // 校验类访问权限
   if (mbd.getFactoryMethodName() != null)  {
      // 工厂方法实例化
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // 非第一次创建,如prototype 。判断用无参构造,还是构造函数依赖注入来实例化
   boolean resolved = false;
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            resolved = true;
            autowireNecessary = mbd.constructorArgumentsResolved;
         }
      }
   }
   if (resolved) {
      if (autowireNecessary) {
         // 构造函数依赖注入
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
         // 无参构造函数
         return instantiateBean(beanName, mbd);
      }
    }
   // 是否采用有参构造函数
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
      // 构造函数依赖注入
      return autowireConstructor(beanName, mbd, ctors, args);
   }
   // (默认) 调用无参构造函数
   return instantiateBean(beanName, mbd);
}

默认会采用无参构造函数

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
   try {
      Object beanInstance;
      final BeanFactory parent = this;
      if (System.getSecurityManager() != null) {
        // 实例化
                beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
                        getInstantiationStrategy().instantiate(mbd, beanName, parent),
                        getAccessControlContext());
            }
      else {
         // 实例化
         beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
      }
      // 包装一下,返回
      BeanWrapper bw = new BeanWrapperImpl(beanInstance);
      initBeanWrapper(bw);
      return bw;
   } ***
}

可以看到,关键在于getInstantiationStrategy().instantiate(mbd, beanName, parent)在进行实际的实例化。

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    // 如果不存在需要被重写的方法,就不用cglib,使用反射
    if (!bd.hasMethodOverrides()) {
        ***
        // 通过构造方法实例化
        return BeanUtils.instantiateClass(constructorToUse);
    } else {
        // 存在方法覆写,通过cglib生成
        return instantiateWithMethodInjection(bd, beanName, owner);
    }
}

到这里,Bean 初始化完成了。

2. 属性装配

populateBean(beanName, mbd, instanceWrapper);

属性装配,也就是注入。对已实例化好的 bean 的属性进行赋值, 如果 bean 中关联着其他 bean,也会帮建立 bean 间的关系。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    ***
    // bean 实例的所有属性。获取待注入的property,配置文件中的<property>也将在这里被处理
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    ***
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // 按照名字获取属性
        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // 按照类型获取属性
        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }
    ***
    if (hasInstAwareBpps) {
        ***
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                ***
                if (pvsToUse == null) {
                    ***
                    // 后置处理器处理@Autowired @Resource等注解
                    pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    ***
                }
                pvs = pvsToUse;
            }}}
    // 注入 <property> 属性
    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

这里有个很重要的地方,处理 Bean 间的依赖注入,说白点就是 @Autowored 注解。

ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);

在对 Bean 赋值时,会先去处理该 Bean 中注入的 Bean,因此对于相互注入的 Bean 来说不用担心 Bean 的生成先后顺序问题。

3. 初始化

exposedObject = initializeBean(beanName, exposedObject, mbd);

属性注入完成后,这一步就是处理各种回调了。

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        // 1. 如bean实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 接口,回调
        invokeAwareMethods(beanName, bean);
    }
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 2. 执行BeanPostProcessor预初始化方法:postProcessBeforeInitialization 
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    try {
        // 3. 处理自定义的init-method,如实现了InitializingBean接口执行afterPropertiesSet()
        invokeInitMethods(beanName, wrappedBean, mbd);
    }***
    if (mbd == null || !mbd.isSynthetic()) {
        // 执行BeanPostProcessor初始化后回调 postProcessAfterInitialization
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}

可以看到,在Bean 生命周期图里各种初始化操作都是在这里完成的。

  1. 执行一些Aware方法,比如 BeanNameAware的setBeanName(beanName)
  2. 执行 BeanPostProcessor 预初始化方法,例如,@PostConstruct 注解的方法。
  3. 执行 afterPropertiesSet() 方法与自定义的 inti-method
  4. 执行 BeanPostProcessor 初始化后方法

4. 销毁

最后就是销毁。这个销毁当然不是指对象被 GC 的销毁。

registerDisposableBeanIfNecessary(beanName, bean, mbd);

register, 这里是在进行销毁逻辑的注册,在销毁时会执行。

比如使用@Bean(destroyMethod = "***")

SpringBoot 回来啦

好了,SpringFramework 的工作结束了,还记得开头的SpringApplication.run吗, 还没执行完呢。

        // 5:刷新容器
        refreshContext(context);
     // 6:Spring容器后置处理
        afterRefresh(context, applicationArguments);
      // 7:发出结束执行的事件
        listeners.started(context);
        // 8:执行Runners
        this.callRunners(context, applicationArguments);
        stopWatch.stop();
        // 9. 返回容器
        return context;

现在 步骤5 容器已经刷新了,之后还有:

(6). afterRefresh

扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理。

(7).listeners.started

发布结束执行事件

(8). this.callRunners

区分ApplicationRunnerCommandLineRunner, 执行run方法。

可以自定义 ApplicationRunner 或 CommandLineRunner,实现 run 方法,注入到容器中, 在SpringBoot 启动后,就会执行所有的 runner 的 run 方法。

(9). return context

终于 run 完了,返回容器。

总结

SpringApplication.run开始,我们所看到的简单的一行代码背后却有这么多弯弯绕。

以上很多地方只是浅尝辄止或一笔带过,主要谈了 IOC 和 Bean有关的主流程,尚有很多比如何解决循环依赖、为何 @Transactional 同类调用会失效等等一些称得上常见的问题,都可以在这里找到答案。

本文主要为了对 SpringBoot 乃至 SpringFramework 的启动流程有个基本的认识,但一叶知秋透过这些不难看出很多巧妙的设计和思路。

话说回来,有时会想,若非热爱和 interview,读源码或深究原理用处何在?

转念又一想,提笔成文是基于大量阅读乃至背诵的。但编码一如识了字、懂些寻常语法便仗键天涯,虽二者不可一概,但总有共通之处。

俗话说,“学而不思则罔”,对比文字逻辑性更强的代码,很难初窥门径便读名家之作。所以我觉得,目的性是要浓厚一些,无论是出发点还是阅读姿势。

俗话说,“学而不思则罔”,比文字逻辑性更强的代码,很难初窥门径便读大师之作。所以我觉得目的性是要热烈一些,不论是出发点还是阅读姿势。一为解决问题而究其根源,二为习名家之法长己身之技,三为做些大家都不想做但又想做的事情。

参考

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇