《springboot源码系列》——自动装配原理

自动装配原理

  springboot的核心就是自动装配、开箱即用。我们的启动类都加上 @SpringBootApplication 注解,它是个复合注解里面包含了 @EnableAutoConfiguration 、默认开启自动装配。
  他会扫描工程中所依赖 jar 的 spring.factories 配置文件,里面就注册了这个框架的 XXXAutoConfiguration 。每个第三方框架的 XXXAutoConfiguration类都有@Conditional 注解指定他生效的条件,这个条件类似于,比如你有没有引入指定的依赖、有没有给个什么配置、或者某个bean之内的。
  然后如果符合生效的条件,那么此时就会对XXXAutoConfiguration中定义的bean进行实例化、根据你在配置文件中的属性、实例化bean,注入到spring容器中。最后你就可以在项目中用了。

启动流程

  我们启动 springboot 项目都是通过 SpringApplication.run(Class, args); 来启动的,跟着源码一步步跟进去可以看到是 new SpringApplication(primarySources).run(args)。也就是说可以分为两步:1 创建 SpringApplication ; 2 run 启动。

创建 SpringApplication

辅助判断

  上面就是创建 SpringApplication 的核心源码了,我们先看 deduceFromClasspath() 。它里面写死了一些类,然后类路径开始扫描你所有类和依赖jar的类,如果扫到他内置写死的类,就说明你的工程类型是 servlet,Java web 工程,应该作为基于servlet的web应用程序运行,并且应该启动嵌入式servlet web服务器。

 

初始化第三方jar扩展点

  紧接着,两次调用 getSpringFactoriesInstances() ,去扫描spring 容器的 ApplicationContextIntializer、ApplicationListener 。他们都是接口,可以被 自定义类 或者 依赖jar 去实现,springboot 获取到了他们之后,会先暂存起来。

   这个方法点进去,最终是执行了 SpringFactoriesLoader.loadFactoryNames(type, classLoader)); 可以看到这里印证了我们上面说的扫描所有依赖jar 的 META-INF/spring.factories 所有的配置类。

   最后执行到了最后一行 this.mainApplicationClass = deduceMainApplicationClass(); 来扫描哪个类包含了 main 方法。然后将这个类作为你的启动类!至此,SpringApplication创建完成。

 

运行run()

  run()点击来,上面几行没啥实际意义,然后扫描实现了 RunListeners 了的类,然后 listeners.starting(); 回调他们的方法。

 

  然后通过 prepareEnvironment() 获取环境配置。

初始化spring容器

  context = createApplicationContext();
  紧接着,这个方法里面通过 AnnotationConfigServletWebServerApplicationContext 初始化了spring容器。

准备容器

  接着就执行了 prepareContext(),主要是初步执行第三方jar扩展点,加入spring容器中。其实核心代码就是在 applyInitializers 对扫描第三方框架的AutoConfiguration进行初始化。

执行的扩展点(自动装配)

  refreshContext()这里就会对 spring容器 进行refresh操作了、执行容器中的所有bean。代码逻辑比较繁琐,我这里直接贴出来调用路径。refreshContext(context); ——> refresh(context); ——> refresh()

启动内置tomcat

  首先在执行 onRefresh() 的时候,被子类 ServletWebServerApplicationContext 重写了该方法,它里面就是调用了 tomcat 原生的api创建了 webserver并启动。

初始化bean

 然后继续往下走到了 finishBeanFactoryInitialization(beanFactory);到了这里 beanFactory.preInstantiateSingletons(); 就是springboot的自动装配了。会将所有第三方jar的的bean实例化好、比如redis、mybatis,以及我们自己写的 controller、service 之内的。并注入到spring中去。

 

posted @ 2021-07-03 14:04  吴磊的  阅读(203)  评论(0编辑  收藏  举报
//生成目录索引列表