一、构造器初始化
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(Class<?>... primarySources) { this(null, primarySources); } public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { //此时为null,可以通过此参数指定类加载器 this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); //封装传进来的启动类 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //推断应用类型reactive,servlet this.webApplicationType = WebApplicationType.deduceFromClasspath(); //初始化classpath下 META-INF/spring.factories中配置的ApplicationContextInitializer //主要通过构造器反射创建 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //初始化classpath下所有配置的 ApplicationListener(META-INF/spring.factories) setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }
二、run方法
public ConfigurableApplicationContext run(String... args) { //记录启动时间 StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); //java.awt.headless是J2SE的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置 // 很多监控工具如jconsole 需要将该值设置为true,系统变量默认为true configureHeadlessProperty(); //从META-INF/spring.factories中获取监听器 SpringApplicationRunListeners //也是通过构造器实例化,但并没有放入IOC容器 SpringApplicationRunListeners listeners = getRunListeners(args); //遍历回调SpringApplicationRunListeners的starting方法 listeners.starting(); try { //封装命令行参数 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //构造应用上下文环境,完成后回调SpringApplicationRunListeners的environmentPrepared方法 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); //判断是否后续处理需要忽略的Bean configureIgnoreBeanInfo(environment); //打印banner Banner printedBanner = printBanner(environment); //根据是否web环境创建相应的IOC容器 context = createApplicationContext(); //实例化SpringBootExceptionReporter,用来支持报告关于启动的错误 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class<?>[] { ConfigurableApplicationContext.class }, context); //完成启动类的加载 //准备上下文环境,将environment设置到IOC容器中 //执行applyInitializers,遍历回调ApplicationContextInitializer的initialize方法 //遍历回调SpringApplicationRunListeners的contextPrepared方法 //遍历回调SpringApplicationRunListeners的contextLoaded方法 prepareContext(context, environment, listeners, applicationArguments, printedBanner); //完成容器的初始化,bean的生命周期 refreshContext(context); //空方法,子类扩展实现 afterRefresh(context, applicationArguments); //启动完成,时间截止 stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //发布容器启动完成事件 listeners.started(context); //从IOC容器获取所有的ApplicationRunner(先调用)和CommandLinedRunner进行回调 callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { //执行配置文件中的监听器的running方法 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
1、记录启动时间
2、SpringApplicationRunListeners监听器实例化
3、调用监听器的starting方法
void starting() { for (SpringApplicationRunListener listener : this.listeners) { listener.starting(); } } //EventPublishingRunListener public void starting() { //关键代码,这里是创建application启动事件:ApplicationStartingEvent发布启动事件 this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); } public void multicastEvent(ApplicationEvent event) { multicastEvent(event, resolveDefaultEventType(event)); } 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 { //执行listener的onApplicationEvent方法,这里有一个关键的listener,BackgroundPreinitializer invokeListener(listener, event); } } } protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) { ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) { try { doInvokeListener(listener, event); } catch (Throwable err) { errorHandler.handleError(err); } } else { doInvokeListener(listener, event); } } private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { listener.onApplicationEvent(event); } catch (ClassCastException ex) { ··· } }
BackgroundPreinitializer
//BackgroundPreinitializer public void onApplicationEvent(SpringApplicationEvent event) { if (!Boolean.getBoolean(IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME) && event instanceof ApplicationStartingEvent && multipleProcessors() && preinitializationStarted.compareAndSet(false, true)) { //执行此方法 performPreinitialization(); } if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) && preinitializationStarted.get()) { try { preinitializationComplete.await(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } } private void performPreinitialization() { try { Thread thread = new Thread(new Runnable() { //初始化一些转换器 @Override public void run() { runSafely(new ConversionServiceInitializer()); runSafely(new ValidationInitializer()); runSafely(new MessageConverterInitializer()); runSafely(new JacksonInitializer()); runSafely(new CharsetInitializer()); preinitializationComplete.countDown(); } public void runSafely(Runnable runnable) { try { runnable.run(); } catch (Throwable ex) { // Ignore } } }, "background-preinit"); thread.start(); } catch (Exception ex) { preinitializationComplete.countDown(); } }
4、封装入参
5、构建应用上下文环境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { //创建并配置相应的环境,获取对应的ConfigurableEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); //根据用户配置,配置 environment系统环境 configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); //发布监听事件,调用的是ConfigFileApplicationListener的onApplicationEvent方法 //这个就是加载项目配置文件的监听器 listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; } //根据环境创建对应ConfigurableEnvironment private ConfigurableEnvironment getOrCreateEnvironment() { if (this.environment != null) { return this.environment; } switch (this.webApplicationType) { case SERVLET://Web程序 return new StandardServletEnvironment(); case REACTIVE://响应式web环境 return new StandardReactiveWebEnvironment(); default://普通程序 return new StandardEnvironment(); } } protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { if (this.addConversionService) { ConversionService conversionService = ApplicationConversionService.getSharedInstance(); environment.setConversionService((ConfigurableConversionService) conversionService); } // 将main 函数的args封装成 SimpleCommandLinePropertySource 加入environment中。 configurePropertySources(environment, args); // 激活相应的配置文件 configureProfiles(environment, args); }
6、配置需要忽略的bean
7、打印Banner
8、根据应用类型创建相应的容器
9、实例化启动报告
9、容器预启动,这里也是加载启动类的地方,之前已经分析过了
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { //环境配置 context.setEnvironment(environment); //执行容器后置处理 postProcessApplicationContext(context); // 执行容器中ApplicationContextInitializer实现类的initialize方法 // 包括spring.factories和通过三种方式自定义的 applyInitializers(context); //向各个监听器发送容器已经准备好的事件 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); //将main函数中的args参数封装成单例Bean,放进进容器 beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { //将 printedBanner 封装成单例,注册进容器 beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } //拿到启动类 Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); //sources就是启动类,这里面把启动类注册成了一个beanDefinition load(context, sources.toArray(new Object[0])); //发布容器已加载事件 listeners.contextLoaded(context); }
//这里默认不执行任何逻辑,因为beanNameGenerator和resourceLoader默认为空。springBoot预留的扩展处理方式,配置上下文的 bean 生成器及资源加载器 protected void postProcessApplicationContext(ConfigurableApplicationContext context) { //如果设置了是beanName生成器,注册到Spring容器中 if (this.beanNameGenerator != null) { context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator); } // 如果设置了资源加载器,设置到Spring容器中 if (this.resourceLoader != null) { if (context instanceof GenericApplicationContext) { ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader); } if (context instanceof DefaultResourceLoader) { ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader()); } } if (this.addConversionService) { context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance()); } }
10、完成IOC容器的加载,这里也是tomcat启动地方,之前也已经分析过了,其他的就是spring源码里面的refresh方法了
11、定义了一个空方法,留给子类扩展
12、容器启动完成,记录截至时间
13、发布容器初始化完成事件
14、调用ApplicationRunner(先调用)和CommandLinedRunner的实现类的run方法,可以自己实现这两个接口,会在容器初始化完成后被调用
15、执行监听器的running方法,发布的是一个ApplicationReadyEvent事件
启动源码解析完毕!