/** * SpringApplication.run方法 */ public ConfigurableApplicationContext run(String... args) { // 用来记录启动时间的类 StopWatch stopWatch = new StopWatch(); // 记录启动时间 stopWatch.start(); // 定义变量 ConfigurableApplicationContext context = null; // 创建一个异常报告集合 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); // 配置headless属性为true(服务器没有显示屏什么的, // 你得告诉程序一声,你工作的地方没有这些设备。如果需要,自己模拟) configureHeadlessProperty(); // 获取运行监听器,这里获取到的是EventPublishingRunListener SpringApplicationRunListeners listeners = getRunListeners(args); // 调用监听器的开始方法,内部会批量的调用监听器(EventPublishingRunListener)的starting方法, // 以发送事件等来间接调用ApplicationListener的onApplicationEvent方法 listeners.starting(); try { // 创建参数类 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 跳过对BeanInfo的搜索 configureIgnoreBeanInfo(environment); // 打印banner(spring图案和版本信息等) Banner printedBanner = printBanner(environment); // 创建应用程序上下文对象(默认为AnnotationConfigServletWebServerApplicationContext对象) GenericWebApplicationContext context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; } /** * SYSTEM_PROPERTY_JAVA_AWT_HEADLESS值为java.awt.headless * 服务器没有显示屏什么的,你得告诉程序一声,你工作的地方没有这些设备。 * 如果需要,自己模拟,默认为true */ private void configureHeadlessProperty() { System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless))); } private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; // 创建一个SpringApplicationRunListeners,参数为getSpringFactoriesInstances获取到的实例 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); } private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { // 获取加载器,底层逻辑是先获取resourceLoader的类加载器, // 没有的话然后用ClassUtils.getDefaultClassLoader();获取默认的类加载器 ClassLoader classLoader = getClassLoader(); // 根据类型获取spring.factories中符合的类名 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 根据以上获取的类名创建类的实例 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); // 将实例进行排序 AnnotationAwareOrderComparator.sort(instances); return instances; } /** * 获取key值是factoryType的列表 */ public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { // 获取传入的class的name String factoryTypeName = factoryType.getName(); // 从spring.factories中获取指定的类型,如果没有的话,返回一个空List return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { // 从缓存中根据类加载器获取MultiValueMap(value为类名list) MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } // 缓存中没有获取到的话 // FACTORIES_RESOURCE_LOCATION META-INF/spring.factories // 使用指定类加载器获取所有包中的META-INF/spring.factories try { Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); // 从指定位置加载 Properties Properties properties = PropertiesLoaderUtils.loadProperties(resource); // 遍历 Properties 中的键值对 for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryTypeName, factoryImplementationName.trim()); } } } // 将spring.factories中的键值对结果以类加载器为key存入缓存中,以便下次调用直接从缓存中读取 cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } } private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<>(names.size()); for (String name : names) { try { // 根据类加载器和类名获取Class对象 Class<?> instanceClass = ClassUtils.forName(name, classLoader); // instanceClass必须为type的子类 Assert.isAssignable(type, instanceClass); // 根据参数获取此类的构造器 Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes); // 根据传入的构造器对象以及构造器所需的参数创建一个实例 T instance = (T) BeanUtils.instantiateClass(constructor, args); // 将创建好的实例添加到集合中 instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); } } return instances; } private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // 创建或者获取一个ConfigurableEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 配置 property sources 和 profiles configureEnvironment(environment, applicationArguments.getSourceArgs()); // 给指定的environment添加一个ConfigurationPropertySource的支持 ConfigurationPropertySources.attach(environment); // 触发环境配置相关的监听事件 listeners.environmentPrepared(environment); // 将配置文件中的spring.main开头的配置信息绑定到SpringApplication类对应的属性中 bindToSpringApplication(environment); if (!this.isCustomEnvironment) { // 转换environment类型 environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } // 给指定的environment添加一个ConfigurationPropertySource的支持 ConfigurationPropertySources.attach(environment); return environment; } /** * 根据webApplicationType类型创建不同的environment */ private ConfigurableEnvironment getOrCreateEnvironment() { if (this.environment != null) { return this.environment; } switch (this.webApplicationType) { case SERVLET: return new StandardServletEnvironment(); case REACTIVE: return new StandardReactiveWebEnvironment(); default: return new StandardEnvironment(); } } class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment { public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams"; public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams"; public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties"; /** * 向propertySources中添加propertySources,目前是空的 * Stub 存根,站位,差不多意思就是目前是空的,占个位置 */ @Override protected void customizePropertySources(MutablePropertySources propertySources) { propertySources.addLast(new PropertySource.StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME)); propertySources.addLast(new PropertySource.StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME)); if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) { propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME)); } super.customizePropertySources(propertySources); } /** * 这是初始化servletProperties方法,此方法会在启动流程的刷新容器方法中被调用,会将上面的propertySource 的值进行填充 */ @Override public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) { WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig); } } class StandardEnvironment extends AbstractEnvironment { public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment"; public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties"; @Override protected void customizePropertySources(MutablePropertySources propertySources) { // 向propertySources 添加二个propertySource,一个是系统的属性,一个是系统的环境,直接就是有值的 // getSystemProperties() 会获得系统的属性值 // getSystemEnvironment() 会获得系统的环境值 propertySources.addLast( new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties())); propertySources.addLast( new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment())); } } protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { if (this.addConversionService) { // 采用单例模式获取一个ConversionService 对象 // ConversionService用于类型转化,我看了下加载完之后有136个转换器,例如String-》Number // 在此之前EventPublishingRunListener中发送的starting() 事件触发了一个BackgroundPreinitializer // 对此进行了预初始化 ConversionService conversionService = ApplicationConversionService.getSharedInstance(); // 将类型转换对象设置到环境中去 environment.setConversionService((ConfigurableConversionService) conversionService); } // 配置属性资源 configurePropertySources(environment, args); // 配置哪个配置文件生效 configureProfiles(environment, args); } protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) { // 获取环境对象中的PropertySources,系统属性 系统环境 servletConfigInitParams servletContextInitParams MutablePropertySources sources = environment.getPropertySources(); // 看看启动SpringApplicaiton的时候,有没有设置默认的属性以键值对的形式,有的话就加进去 if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) { sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties)); } // addCommandLineProperties默认为true,如果启动时传入了参数 if (this.addCommandLineProperties && args.length > 0) { // name值为commandLineArgs String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME; // 如果sources中包含name if (sources.contains(name)) { // 根据name获取到该source PropertySource<?> source = sources.get(name); // 以commandLineArgs 为key 创建一个CompositePropertySource(符合资源对象)对象 CompositePropertySource composite = new CompositePropertySource(name); // 向composite里加入 一个以springApplicationCommandLineArgs为key,传入的参数为值的PropertySource composite.addPropertySource( new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args)); // 并且将source 也加入到 composite中 composite.addPropertySource(source); // 用composite替换原来对象 // 将属性中的命令行参数和spring启动的参数都放进composite中,并用composite替换原来的值 sources.replace(name, composite); } // 如果只有spring启动传入的参数的话,则以commandLineArgs为key,参数为值添加到最sources的最前面 else { sources.addFirst(new SimpleCommandLinePropertySource(args)); } } } protected void configureProfiles(ConfigurableEnvironment environment, String[] args) { Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles); // 从遍历PropertySources,从中获取属性为spring.profiles.active的属性 profiles.addAll(Arrays.asList(environment.getActiveProfiles())); // 设置环境中生效的profiles,可以同时生效多个 environment.setActiveProfiles(StringUtils.toStringArray(profiles)); } /** * 给指定的环境添加一个ConfigurationPropertySource的支持 * 将环境管理的每个PropertySource调整为ConfigurationPropertySource * 并允许经典的PropertySourcesPropertyResolver调用来解决使用 * 所附的解析器将动态地跟踪底层环境属性源的任何添加或删除 * 目前按我的理解这个绑定就是给所有的sources换了个类型,这个类型提供一些方法可以更好的追踪,删除加入等操作 */ public static void attach(Environment environment) { Assert.isInstanceOf(ConfigurableEnvironment.class, environment); // 获取environment中的PropertySources MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources(); // 获取sources中的configurationProperties PropertySource<?> attached = sources.get(ATTACHED_PROPERTY_SOURCE_NAME); // 如果sources 中含有 configurationProperties,并且其中的source不是最新的,则移除他 if (attached != null && attached.getSource() != sources) { sources.remove(ATTACHED_PROPERTY_SOURCE_NAME); attached = null; } // 在sources的最前面添加ConfigurationPropertySourcesPropertySource类型的configurationProperties if (attached == null) { sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME, new SpringConfigurationPropertySources(sources))); } } /** * 调用environmentPrepared函数发送环境已经准备好的事件,从而触发监听器执行方法 */ void environmentPrepared(ConfigurableEnvironment environment) { for (org.springframework.boot.SpringApplicationRunListener listener : this.listeners) { // 该方法会间接调用如下方法multicastEvent listener.environmentPrepared(environment); } } @Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); // getApplicationListeners(event, type)会获取到七个监听器 // 七个监听器分别为: //0 = {ConfigFileApplicationListener@2420} 根据传入的参数,以及生效的profile 来加载配置文件 //1 = {AnsiOutputApplicationListener@2421} 用于配置ansi编码 //2 = {LoggingApplicationListener@2422} 根据配置的属性设置配置日志 //3 = {ClasspathLoggingApplicationListener@2423} 根据日志的输出等级打印classpath的信息 //4 = {BackgroundPreinitializer@2424} 在此事件中不会执行操作 //5 = {DelegatingApplicationListener@2425} 在此事件中不会执行操作 //6 = {FileEncodingApplicationListener@2426} 根据配置来判断文件的类型是否符合配置 for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { invokeListener(listener, event); } } } /** * 配置了一个spring.beaninfo.ignore属性,默认为TRUE,跳过对 BeanInfo 的搜索, * 这个BeanInfo是JDK 声明的一个接口,可以使用Introspector.getBeanInfo获取一个对象的方法、属性、事件和其他功能的显式信息。 * 设置spring.beaninfo.ignore,将使用低级反射和应用标准设计模式自动分析某个类的信息,可以提升一些性能。 */ private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) { if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) { Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE); System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString()); } } /** * 该接口对应springApplicaiton.run的各个阶段 * EventPublishingRunListener实现了下面接口 */ interface SpringApplicationRunListener { /** * run方法启动时立即调用,可以用于非常早期的初始化 */ default void starting() { } /** * 在环境准备好,但在ApplicaitonContext创建之前执行 */ default void environmentPrepared(ConfigurableEnvironment environment) { } /** * 在ApplicationContext创建和准备好,但在资源加载前 */ default void contextPrepared(ConfigurableApplicationContext context) { } /** * application context 加载完,但在刷新之前 */ default void contextLoaded(ConfigurableApplicationContext context) { } /** * context 刷新完并且 application 已完成,但是在 CommandLineRunner 和 ApplicationRunner 被调用前 */ default void started(ConfigurableApplicationContext context) { } /** * 在run方法运行结束前调用,当application context 已经刷新 并且 CommandLineRunner 和 ApplicationRunner也已经 * 被调用 */ default void running(ConfigurableApplicationContext context) { } /** * 在运行程序的时候发生错误的时候调用 */ default void failed(ConfigurableApplicationContext context, Throwable exception) { } }