SpringbootCode的启动源码是怎样的
Springboot Code的启动源码是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
创新互联是专业的广水网站建设公司,广水接单;提供网站制作、成都做网站,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行广水网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
项目启动的流程:
(一)new SpringApplication
配置source和web环境;
创建初始化构造器和应用监听器;
配置应用的主方法所在类;
(二)run 第一二部分
1.获取并启动监听器
初始化计时stopWatch、启动上下文bootstrapContext、设置系统参数headless;
初始化监听器列表SpringApplicationRunListeners;
发布springboot开始启动事件(从applicationListeners中过滤出4个能监听ApplicationStartingEvent事件的,并启动它们)
2.准备环境
装配命令行参数applicationArguments(对象中装载4个propertySource);
准备应用程序运行的环境ConfigurableEnvironment(从applicationListeners中过滤出6个能监听ApplicationEnvironmentPreparedEvent事件的,并启动它们。监听器中关联启动了一些后置处理器处理数据,最终目的是为应用环境做准备)
3.打印banner
方法:
public ConfigurableApplicationContext run(String... args) { //1、StopWatch简单的看成一个stop watch的机制,保存stop的记录信息。 //初始化一个计时器,并开始计时 StopWatch stopWatch = new StopWatch(); stopWatch.start(); //初始化启动上下文 DefaultBootstrapContext bootstrapContext = this.createBootstrapContext(); ConfigurableApplicationContext context = null; //2、configureHeadlessProperty即配置headless模式,这种模式是一种系统缺少显示设备、键盘和鼠标外设的情况模式。 this.configureHeadlessProperty(); //3、SpringApplicationListeners为SpringApplicationRunListener接口实现集合(创建SpringApplicationRunListener初始化构造器)初始化监听器列表 //可以理解这个接口就是在spring启动整个过程都需要回调这些listener //debug能发现,拿到了一个名为EventPublishingRunListener(RunListener构造方法中关联上了全部applicationListener),这个就是用来进行触发publishEvent的被观察者 SpringApplicationRunListeners listeners = this.getRunListeners(args); //启动EventPublishingRunListener,从而过滤并启动相关Listener listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //4、ConfigurableEnvironment为配置环境对象,简单理解所有的配置信息汇总在这个对象中 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments); this.configureIgnoreBeanInfo(environment); //5、Banner就是我们常在控制台输出的画面横幅,可以使用图片或者文本进行替换 Banner printedBanner = this.printBanner(environment); =====> //6、ConfigurableApplicationContext根据webApp…Type进行构造的上下文对象 context = this.createApplicationContext(); context.setApplicationStartup(this.applicationStartup); //7、接下来进入关键步骤的第一步:prepareContext,准备容器阶段,将执行所有的initializers逻辑,做初始化准备操作。 this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //8、refreshContext,可以理解成容器初始化节点,将执行bean的创建和实例化。 this.refreshContext(context); //9、afterRefresh,容器后处理, 可以看到会找到ApplicationRunner和CommandLineRunner的实现类并执行。但从2.x版本来看,似乎这个方法是个空方法,applicationRun和commandRun移到启动最后。 this.afterRefresh(context, applicationArguments); //10、然后根据stopwatch打印出启动时间 stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); //11、这里调用ApplicationRunner和CommandLineRunner的实现类 this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
下面开始对context的创建与准备
context = this.createApplicationContext(); protected ConfigurableApplicationContext createApplicationContext() { return this.applicationContextFactory.create(this.webApplicationType); }
public interface ApplicationContextFactory { ApplicationContextFactory DEFAULT = (webApplicationType) -> { try { switch(webApplicationType) { case SERVLET: return new AnnotationConfigServletWebServerApplicationContext(); case REACTIVE: return new AnnotationConfigReactiveWebServerApplicationContext(); default: return new AnnotationConfigApplicationContext(); } } catch (Exception var2) { throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2); } }; ConfigurableApplicationContext create(WebApplicationType webApplicationType); .... }
上述代码可以通过webApplicationTyep(即SERVLET)创建 AnnotationConfigServletWebServerApplicationContext 对象,对象创建过程中,初始化了父类的属性值,其中有三个比较关键的值,reader、scanner和父类中的beanFactory,下面这个对象的层级结构需要了解一下
/** * reader 和 scanner 都是在构造方法中进行了赋值 **/ public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext implements AnnotationConfigRegistry { private final AnnotatedBeanDefinitionReader reader; private final ClassPathBeanDefinitionScanner scanner; private final Set> annotatedClasses; private String[] basePackages; public AnnotationConfigServletWebServerApplicationContext() { this.annotatedClasses = new LinkedHashSet(); this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); } ... }
我们可以在 GenericApplicationContext 类的构造方法中看到其构造方法中,对beanFactory属性的赋值
public GenericApplicationContext() { this.customClassLoader = false; this.refreshed = new AtomicBoolean(); this.beanFactory = new DefaultListableBeanFactory(); }
接下来对context进行配置与准备,看下prepareContext方法
//6、ConfigurableApplicationContext根据webApp…Type进行构造的上下文对象 context = this.createApplicationContext(); context.setApplicationStartup(this.applicationStartup); =====> //7、接下来进入关键步骤的第一步:prepareContext,准备容器阶段,将执行所有的initializers逻辑,做初始化准备操作。 this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //8、refreshContext,可以理解成容器初始化节点,将执行bean的创建和实例化。 this.refreshContext(context); //9、afterRefresh,容器后处理, 可以看到会找到ApplicationRunner和CommandLineRunner的实现类并执行。但从2.x版本来看,似乎这个方法是个空方法,applicationRun和commandRun移到启动最后。 this.afterRefresh(context, applicationArguments); //10、然后根据stopwatch打印出启动时间 stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); //11、这里调用ApplicationRunner和CommandLineRunner的实现类 this.callRunners(context, applicationArguments);
/** * Spring容器准备 */ private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 设置上下文环境 context.setEnvironment(environment); // postProcessApplicationContext(context); // 执行所有ApplicationContextInitializer对象的initialize方法(这些对象是通过读取spring.factories加载) applyInitializers(context); // 发布上下文准备完成事件到所有监听器 listeners.contextPrepared(context); bootstrapContext.close(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources Set