注:本系列源码剖析基于spring 5.2.2.RELEASE,本文的发动流程针对于annotation注解办法,gitee库房链接:gitee.com/funcy/sprin….

在前面的文章中,咱们成功的编译了spring源码,也构建了第一个spring测试demo,接下来咱们就基于第一个spring源码调试demo中的代码,来对spring源码进行源码剖析。

1. spring 发动流程概览

在前面 demo 的 main()办法中,有这么一行:

ApplicationContext context =
        new AnnotationConfigApplicationContext("org.springframework.learn.demo01");

这短短的一行便是spring的整个发动流程了。上面的代码中,声明晰一个ApplicationContext类型的目标context,右边运用其子类AnnotationConfigApplicationContext实例化,并在结构办法中传入了包名org.springframework.learn.demo01,这个包名就标明晰接下来要扫描哪些包。

这儿咱们接触到了spring的第一个组件:ApplicationContext,关于ApplicationContext的剖析,能够参阅我的文章spring组件(一):ApplicationContext。

进入到AnnotationConfigApplicationContext,代码如下:

AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String…)

public AnnotationConfigApplicationContext(String... basePackages) {
     // 1. 调用无参结构函数,会先调用父类GenericApplicationContext的结构函数
     // 2. 父类的结构函数里边便是初始化DefaultListableBeanFactory,并且赋值给beanFactory
     // 3. 本类的结构函数里边,初始化了一个读取器:AnnotatedBeanDefinitionReader read,
     //    一个扫描器ClassPathBeanDefinitionScanner scanner
     // 4. 这个scanner,便是下面 scan(basePackages) 调用的目标
     this();
     //对传入的包进行扫描,扫描完结后,会得到一个 BeanDefinition 的集合
     scan(basePackages);
     //发动spring,在这儿完结spring容器的初始化操作,
     //包括bean的实例化、特点注入,将bean保存到spring容器中等
     refresh();
}

这个类就三行,相关操作都已在代码中注释了,这儿略微再总结下,这段代码首要做了三件事:

  1. 调用无参结构,进行特点初始化
  2. 进行包扫描,得到BeanDefinition
  3. 启用spring容器。

接着,咱们再来看看spring发动流程中,做了哪些事:

AbstractApplicationContext#refresh

public void refresh() throws BeansException, IllegalStateException {
    // 运用synchronized是为了防止refresh() 还没结束,再次建议发动或许销毁容器引起的抵触
    synchronized (this.startupShutdownMonitor) {
        // 做一些准备工作,记录容器的发动时刻、标记“已发动”状况、检查环境变量
        prepareRefresh();
        // 初始化BeanFactory容器、注册BeanDefinition, 终究取得了DefaultListableBeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        // 还是一些准备工作:
        // 1. 设置了一个类加载器
        // 2. 设置了bean表达式解析器
        // 3. 增加了特点编辑器的支持
        // 4. 增加了一个后置处理器:ApplicationContextAwareProcessor
        // 5. 设置了一些忽略自动安装的接口
        // 6. 设置了一些允许自动安装的接口,并且进行了赋值操作
        // 7. 在容器中还没有XX的bean的时候,帮咱们注册beanName为XX的singleton bean
        prepareBeanFactory(beanFactory);
        try {
            // Spring的一个扩展点. 如果有Bean完结了BeanFactoryPostProcessor接口,
            // 那么在容器初始化今后,Spring 会担任调用里边的 postProcessBeanFactory 办法。
            // 详细的子类能够在这步的时候增加特殊的 BeanFactoryPostProcessor 的完结类,来做些事
            postProcessBeanFactory(beanFactory);
            // 调用BeanFactoryPostProcessor各个完结类的postProcessBeanFactory(factory) 办法
            invokeBeanFactoryPostProcessors(beanFactory);
            // 扩展点,注册 BeanPostProcessor 的完结类,留意不是BeanFactoryPostProcessor
            registerBeanPostProcessors(beanFactory);
            // 初始化当时 ApplicationContext 的 MessageSource,用在国际化操作中
            initMessageSource();
            // 这个办法首要为初始化当时 ApplicationContext 的事情播送器
            initApplicationEventMulticaster();
            // 这也是spring的一个扩展点
            onRefresh();
            // Check for listener beans and register them.
            // 注册事情监听器
            registerListeners();
            // 初始化一切的 singleton beans
            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.
            // 销毁已经初始化的的Bean
            destroyBeans();
            // Reset 'active' flag.
            // 重置 'active' 状况
            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();
        }
    }
}

这个办法虽然代码不多,但包含了spring bean的整个创立过程,每个办法做了些什么,在代码中都有注释,这儿就不赘述了。

实际上,refresh() 涵盖了spring整个创立bean的流程,在后边的文章中,咱们也将要点展开这儿边的办法来剖析,在现阶段只需要大致了解这些办法做了什么事即可。

整个流程总结如下:

spring启动流程(一):启动流程概览

2. spring发动中beanFactory的改变

本文中的源码解读就到这儿了,接下来咱们来看看,spring发动中beanFactory有些什么改变。

beanFactory 是spring的重要组件之一,直译为spring bean工厂,是spring生产bean与保存bean的当地,关于beanFactory的详细剖析,能够检查spring BeanFactory剖析。

咱们将断点打在AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)this()办法上,然后运转demo01的 main() 办法:

spring启动流程(一):启动流程概览

此刻的变量中,并没有beanFactory,咱们自己增加beanFactory到调度窗口的变量列表中:

spring启动流程(一):启动流程概览

这样就能看到对应的值了:

spring启动流程(一):启动流程概览

能够看到,此刻的beanFactory为null,标明beanFactory并未实例化,咱们持续运转:

spring启动流程(一):启动流程概览

当运转完this()后,发现beanFactory已经有值了,类型为DefaultListableBeanFactory。可是,在检查beanFactory目标时,发现beanFactory的特点太多了,咱们应该要点重视啥呢?

spring启动流程(一):启动流程概览

咱们这部分首要重视spring bean的创立,因而只需要重视beanFactory的两个特点就能够了:

  • beanDefinitionMap:寄存beanDefinition的map.
  • singletonObjects:寄存spring bean的map,spring bean创立后都寄存在这儿,也即直观上理解的spring 容器.

BeanDefinition 是spring重要组件之一,为‘spring bean的描绘’,简略来说,便是说明晰一个spring bean应该如何创立。关于BeanDefinition的详细剖析,能够检查spring BeanDefinition剖析。

咱们手动增加变量,如下:

spring启动流程(一):启动流程概览

能够看到,此刻的beanDefinitionMap中已经有4个目标了,明显是在this()办法中增加的,关于这块咱们后边会剖析。

接着运转,发现beanDefinitionMap又多了两个:

spring启动流程(一):启动流程概览

这儿的beanObj1beanObj2便是咱们自己的类了,由此能够判断出spring便是在AnnotationConfigApplicationContext#scan办法中对包进行扫描的

接下来,代码执行进入AbstractApplicationContext#refresh办法,咱们一行行运转下去,发现运转到prepareBeanFactory(beanFactory);时,singletonObjects中第一次呈现了目标:

spring启动流程(一):启动流程概览

能够看到,这儿呈现了3个类,根本都跟系统、环境相关,如environment是spring当时运用的环境(profile),systemProperties 当时系统的特点(操作系统、操作系统版别等)。

持续往下运转,发现代码运转到invokeBeanFactoryPostProcessors(beanFactory)时,又多了4个类:

spring启动流程(一):启动流程概览

关于这几个类的效果,咱们后边的文章中会剖析,这儿先不必管。持续往下运转,发现在registerBeanPostProcessors(beanFactory);中,又多了一个目标:

org.springframework.context.annotation.internalAutowiredAnnotationProcessor

这儿咱们依旧不必管这个目标,接着运转下去,能够看到在运转initMessageSource()时,又多了一个目标:

messageSource -> {DelegatingMessageSource@1847} "Empty MessageSource"

明显,这个目标是用来处理国际化问题的,不过由于demo01中并没有用到国际化,所以这儿显现Empty MessageSource。持续运转,发现运转到initApplicationEventMulticaster();时,又多了一个目标:

applicationEventMulticaster -> {SimpleApplicationEventMulticaster@1869}

明显,这个目标是用来处理ApplicationContext 的播送事情的,咱们的demo中并没有用到,暂时不必理会。持续下去,发现在运转完finishBeanFactoryInitialization(beanFactory);singletonObjects中总算呈现了咱们期待的目标:

spring启动流程(一):启动流程概览

由此可见,目标便是在该办法中创立的。

总结

  1. spring 包的描绘:AnnotationConfigApplicationContext#scan
  2. spring bean的创立:AbstractApplicationContext#finishBeanFactoryInitialization

本文首要是了解spring 发动流程,从全体上掌握spring发动过程中的beanFactory的改变。本文意在了解spring的全体发动流程,后续的剖析中,咱们将对这些流程进行展开剖析。


本文原文链接:my.oschina.net/funcy/blog/… ,限于作者个人水平,文中难免有错误之处,欢迎纠正!原创不易,商业转载请联络作者取得授权,非商业转载请注明出处。

本系列的其他文章

【spring源码剖析】spring源码剖析系列目录