SpringBoot启动流程解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: SpringBoot启动流程解析

由于该系统是底层系统,以微服务形式对外暴露dubbo服务,所以本流程中SpringBoot不基于jetty或者tomcat等容器启动方式发布服务,而是以执行程序方式启动来发布(参考下图keepRunning方法)。


 本文以调试一个实际的SpringBoot启动程序为例,参考流程中主要类类图,来分析其启动逻辑和自动化配置原理。

总览:

 上图为SpringBoot启动结构图,我们发现启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块,第三部分是自动化配置模块,该模块作为springboot自动配置核心,在后面的分析中会详细讨论。在下面的启动程序中我们会串联起结构中的主要功能。

启动:

 每个SpringBoot程序都有一个主入口,也就是main方法,main里面调用SpringApplication.run()启动整个spring-boot程序,该方法所在类需要使用@SpringBootApplication注解,以及@ImportResource注解(if need),@SpringBootApplication包括三个注解,功能如下:@EnableAutoConfiguration:SpringBoot根据应用所声明的依赖来对Spring框架进行自动配置


@SpringBootConfiguration(内部为@Configuration):被标注的类等于在spring的XML配置文件中(applicationContext.xml),装配所有bean事务,提供了一个spring的上下文环境


@ComponentScan:组件扫描,可自动发现和装配Bean,默认扫描SpringApplication的run方法里的Booter.class所在的包路径下文件,所以最好将该启动类放到根包路径下

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

// SpringApplication#run
  public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    return new SpringApplication(primarySources).run(args);
  }

// 构建SpringApplication
  public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 探测webApplicationType 类型,根据是否出现"javax.servlet.Servlet",
    // "org.springframework.web.context.ConfigurableWebApplicationContext"
    // 等判断
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // getSpringFactoriesInstances => SpringFactoriesLoader.loadFactoryNames() => loadSpringFactories(),解释见下面
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
  }

SpringFactoriesLoader# loadSpringFactories()会扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。

  private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap<String, String> result = cache.get(classLoader);
    if (result != null) {
      return result;
    }

    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 = PropertiesLoaderUtils.loadProperties(resource);
        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());
          }
        }
      }
      cache.put(classLoader, result);
      return result;
    }
    catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load factories from location [" +
          FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
  }

result中的值为:

getSpringFactoriesInstances(ApplicationContextInitializer.class)和getSpringFactoriesInstances(ApplicationListener.class))都是从刚才扫描结果获取到相应的值。

getSpringFactoriesInstances(ApplicationContextInitializer.class)的值:

getSpringFactoriesInstances(ApplicationListener.class))的值

   接下来回到SpringApplication# run()

  public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();
    try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      configureIgnoreBeanInfo(environment);
      Banner printedBanner = printBanner(environment);
      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;
  }

该方法中实现了如下几个关键步骤:

1.创建了应用的监听器SpringApplicationRunListeners并开始监听

2.prepareEnvironment()加载SpringBoot配置环境(ConfigurableEnvironment),如果是通过web容器发布,会加载StandardEnvironment,其最终也是继承了ConfigurableEnvironment,类图如下

可以看出,*Environment最终都实现了PropertyResolver接口,我们平时通过environment对象获取配置文件中指定Key对应的value方法时,就是调用了propertyResolver接口的getProperty方法


3.配置环境(Environment)加入到监听器对象中(SpringApplicationRunListeners)


4.创建run方法的返回对象:ConfigurableApplicationContext(应用配置上下文),我们可以看一下创建方法:

  protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
      try {
        switch (this.webApplicationType) {
        case SERVLET:
          contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
          break;
        case REACTIVE:
          contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
          break;
        default:
          contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
        }
      }
      catch (ClassNotFoundException ex) {
        throw new IllegalStateException(
            "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
      }
    }
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
  }

方法会先获取显式设置的应用上下文(applicationContextClass),如果不存在,再加载默认的环境配置(通过是否是web environment判断),默认选择AnnotationConfigApplicationContext注解上下文(通过扫描所有注解类来加载bean),最后通过BeanUtils实例化上下文对象,并返回,ConfigurableApplicationContext类图如下:

主要看其继承的两个方向:

LifeCycle:生命周期类,定义了start启动、stop结束、isRunning是否运行中等生命周期空值方法

ApplicationContext:应用上下文类,其主要继承了beanFactory(bean的工厂类)

   接下来继续回到SpringApplication# run()中,先看prepareContext()方法

  public ConfigurableApplicationContext run(String... args) {
    ...
      context = createApplicationContext();
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
          new Class[] { ConfigurableApplicationContext.class }, context);
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      refreshContext(context);
      afterRefresh(context, applicationArguments);
    ... 
    return context;
  }

prepareContext方法将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联,同时会执行applyInitializers(context);

protected void applyInitializers(ConfigurableApplicationContext context) {
    // getInitializers()的值是在上文中setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));设置进入的
    for (ApplicationContextInitializer initializer : getInitializers()) {
      Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
          ApplicationContextInitializer.class);
      Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
      initializer.initialize(context);
    }
  }

接下来的refreshContext(context)

refreshContext(context)方法(初始化方法如下)将是实现spring-boot-starter-*(mybatis、redis等)自动化配置的关键,包括spring.factories的加载,bean的实例化等核心工作。

其调用顺序:refreshContext(context) => refresh(context) => ((AbstractApplicationContext) applicationContext).refresh()

refresh方法配置结束后,Springboot做了一些基本的收尾工作,返回了应用环境上下文。回顾整体流程,Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并基于以上条件,在容器中开始实例化我们需要的Bean,至此,通过SpringBoot启动的程序已经构造完成,接下来我们来探讨自动化配置是如何实现。

总结下springboot启动流程

根据配置信息决定创建什么类型的applicationContext(AnnotationConfigServletWebServerApplicationContext)

=> 然后刷新 refresh(), 刷新主要做了以下几件事:

1、做整备工作

2、invokeBeanFactoryPostProcessors执行BeanFactoryPostProcessor的方法,其中一步是执行ConfigurationClassPostProcessor

3、ConfigurationClassPostProcessor是一个BeanDefinitionRegistryPostProcessor**

**它会解析完成所有的@Configuration配置类,然后所有@Bean、@ComponentScan等等Bean定义都会搜集进来了。它解析的对象(beans),要么从xml解析出来的(包含扫描),要么(springboot)是 @SpringBootApplication 扫描出来的。

4、registerBeanPostProcessors注册BeanPostProcessor(Bean的后置处理器)

5、finishBeanFactoryInitialization(beanFactory);初始化所有剩下的单实例bean

附几张数据

BeanDefinition

0 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"
1 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"
2 = "org.springframework.context.annotation.internalCommonAnnotationProcessor"
3 = "org.springframework.context.event.internalEventListenerProcessor"
4 = "org.springframework.context.event.internalEventListenerFactory"
5 = "demoApplication"
6 = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory"
7 = "anotherConfig"
8 = "appConfig"
9 = "thirdConfig"
10 = "errorController"
11 = "helloController"
12 = "myExceptionHandler"
13 = "helloFilter"
14 = "anotherBean"
15 = "myBean"
16 = "thirdBean"
17 = "org.springframework.boot.autoconfigure.AutoConfigurationPackages"
18 = "org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration"
19 = "propertySourcesPlaceholderConfigurer"
20 = "org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration$TomcatWebSocketConfiguration"
21 = "websocketServletWebServerCustomizer"
22 = "org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration"
23 = "org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat"
24 = "tomcatServletWebServerFactory"
25 = "org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration"
26 = "servletWebServerFactoryCustomizer"
27 = "tomcatServletWebServerFactoryCustomizer"
28 = "org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor"
29 = "org.springframework.boot.context.internalConfigurationPropertiesBinderFactory"
30 = "org.springframework.boot.context.internalConfigurationPropertiesBinder"
31 = "org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator"
32 = "org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata"
33 = "server-org.springframework.boot.autoconfigure.web.ServerProperties"
34 = "webServerFactoryCustomizerBeanPostProcessor"
35 = "errorPageRegistrarBeanPostProcessor"
36 = "org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletConfiguration"
37 = "dispatcherServlet"
38 = "spring.mvc-org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties"
39 = "spring.http-org.springframework.boot.autoconfigure.http.HttpProperties"
40 = "org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration"
41 = "dispatcherServletRegistration"
42 = "org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration"
43 = "org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration"
44 = "taskExecutorBuilder"
45 = "applicationTaskExecutor"
46 = "spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties"
47 = "org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration"
48 = "defaultValidator"
49 = "methodValidationPostProcessor"
50 = "org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration"
51 = "error"
52 = "beanNameViewResolver"
53 = "org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration$DefaultErrorViewResolverConfiguration"
54 = "conventionErrorViewResolver"
55 = "org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration"
56 = "errorAttributes"
57 = "basicErrorController"
58 = "errorPageCustomizer"
59 = "preserveErrorControllerTargetClassPostProcessor"
60 = "spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties"
61 = "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration"
62 = "requestMappingHandlerAdapter"
63 = "requestMappingHandlerMapping"
64 = "welcomePageHandlerMapping"
65 = "mvcConversionService"
66 = "mvcValidator"
67 = "mvcContentNegotiationManager"
68 = "mvcPathMatcher"
69 = "mvcUrlPathHelper"
70 = "viewControllerHandlerMapping"
71 = "beanNameHandlerMapping"
72 = "routerFunctionMapping"
73 = "resourceHandlerMapping"
74 = "mvcResourceUrlProvider"
75 = "defaultServletHandlerMapping"
76 = "handlerFunctionAdapter"
77 = "mvcUriComponentsContributor"
78 = "httpRequestHandlerAdapter"
79 = "simpleControllerHandlerAdapter"
80 = "handlerExceptionResolver"
81 = "mvcViewResolver"
82 = "mvcHandlerMappingIntrospector"
83 = "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter"
84 = "defaultViewResolver"
85 = "viewResolver"
86 = "requestContextFilter"
87 = "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration"
88 = "formContentFilter"
89 = "org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration"
90 = "mbeanExporter"
91 = "objectNamingStrategy"
92 = "mbeanServer"
93 = "org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration"
94 = "springApplicationAdminRegistrar"
95 = "org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration"
96 = "org.springframework.boot.autoconfigure.aop.AopAutoConfiguration"
97 = "org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration"
98 = "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$Jackson2ObjectMapperBuilderCustomizerConfiguration"
99 = "standardJacksonObjectMapperBuilderCustomizer"
100 = "spring.jackson-org.springframework.boot.autoconfigure.jackson.JacksonProperties"
101 = "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration"
102 = "jacksonObjectMapperBuilder"
103 = "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$ParameterNamesModuleConfiguration"
104 = "parameterNamesModule"
105 = "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration"
106 = "jacksonObjectMapper"
107 = "org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration"
108 = "jsonComponentModule"
109 = "org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfiguration"
110 = "stringHttpMessageConverter"
111 = "org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration$MappingJackson2HttpMessageConverterConfiguration"
112 = "mappingJackson2HttpMessageConverter"
113 = "org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration"
114 = "org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration"
115 = "messageConverters"
116 = "org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration"
117 = "spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties"
118 = "org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration"
119 = "spring.security.oauth2.resourceserver-org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties"
120 = "org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration"
121 = "taskSchedulerBuilder"
122 = "spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties"
123 = "org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafJava8TimeDialect"
124 = "java8TimeDialect"
125 = "org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafWebMvcConfiguration$ThymeleafViewResolverConfiguration"
126 = "thymeleafViewResolver"
127 = "org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafWebMvcConfiguration"
128 = "org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafDefaultConfiguration"
129 = "templateEngine"
130 = "org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$DefaultTemplateResolverConfiguration"
131 = "defaultTemplateResolver"
132 = "org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration"
133 = "spring.thymeleaf-org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties"
134 = "org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration"
135 = "restTemplateBuilder"
136 = "org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration$TomcatWebServerFactoryCustomizerConfiguration"
137 = "tomcatWebServerFactoryCustomizer"
138 = "org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration"
139 = "org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration"
140 = "characterEncodingFilter"
141 = "localeCharsetMappingsCustomizer"
142 = "org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration"
143 = "multipartConfigElement"
144 = "multipartResolver"
145 = "spring.servlet.multipart-org.springframework.boot.autoconfigure.web.servlet.MultipartProperties"

Singleton

"characterEncodingFilter" -> {OrderedCharacterEncodingFilter@6077} 
"org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration" -> {MultipartAutoConfiguration@6079} 
"org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration" -> {DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration@6081} 
"preserveErrorControllerTargetClassPostProcessor" -> {ErrorMvcAutoConfiguration$PreserveErrorControllerTargetClassPostProcessor@6083} 
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor" -> {ConfigurationClassPostProcessor@6084} 
"propertySourcesPlaceholderConfigurer" -> {PropertySourcesPlaceholderConfigurer@6086} 
"springApplicationArguments" -> {DefaultApplicationArguments@6088} 
"contextAttributes" -> {Collections$UnmodifiableMap@6090}  size = 7
"methodValidationPostProcessor" -> {MethodValidationPostProcessor@6091} "proxyTargetClass=true; optimize=false; opaque=false; exposeProxy=false; frozen=false"
"org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration$TomcatWebServerFactoryCustomizerConfiguration" -> {EmbeddedWebServerFactoryCustomizerAutoConfiguration$TomcatWebServerFactoryCustomizerConfiguration@6093} 
"tomcatServletWebServerFactoryCustomizer" -> {TomcatServletWebServerFactoryCustomizer@6095} 
"server-org.springframework.boot.autoconfigure.web.ServerProperties" -> {ServerProperties@6097} 
"websocketServletWebServerCustomizer" -> {TomcatWebSocketServletWebServerCustomizer@6099} 
"autoConfigurationReport" -> {ConditionEvaluationReport@6101} 
"org.springframework.context.event.internalEventListenerFactory" -> {DefaultEventListenerFactory@6103} 
"servletWebServerFactoryCustomizer" -> {ServletWebServerFactoryCustomizer@6105} 
"org.springframework.boot.context.internalConfigurationPropertiesBinder" -> {ConfigurationPropertiesBinder@6107} 
"webServerFactoryCustomizerBeanPostProcessor" -> {WebServerFactoryCustomizerBeanPostProcessor@6108} 
"org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration" -> {ServletWebServerFactoryAutoConfiguration@6110} 
"systemEnvironment" -> {Collections$UnmodifiableMap@6112}  size = 45
"org.springframework.context.event.internalEventListenerProcessor" -> {EventListenerMethodProcessor@6113} 
"spring.mvc-org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties" -> {WebMvcProperties@6115} 
"localeCharsetMappingsCustomizer" -> {HttpEncodingAutoConfiguration$LocaleCharsetMappingsCustomizer@6117} 
"multipartConfigElement" -> {MultipartConfigElement@6119} 
"formContentFilter" -> {OrderedFormContentFilter@6121} 
"requestContextFilter" -> {OrderedRequestContextFilter@6123} 
"org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator" -> {ConfigurationPropertiesBeanDefinitionValidator@6125} 
"org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration" -> {HttpEncodingAutoConfiguration@6127} 
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor" -> {AutowiredAnnotationBeanPostProcessor@6128} 
"org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry" -> {ConfigurationClassParser$ImportStack@6130}  size = 0
"org.springframework.boot.context.ContextIdApplicationContextInitializer$ContextId" -> {ContextIdApplicationContextInitializer$ContextId@6132} 
"org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory" -> {SharedMetadataReaderFactoryContextInitializer$SharedMetadataReaderFactoryBean@5793} 
"applicationEventMulticaster" -> {SimpleApplicationEventMulticaster@5139} 
"environment" -> {StandardServletEnvironment@4853} "StandardServletEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[ConfigurationPropertySourcesPropertySource {name='configurationProperties'}, StubPropertySource {name='servletConfigInitParams'}, ServletContextPropertySource {name='servletContextInitParams'}, PropertiesPropertySource {name='systemProperties'}, OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'}, RandomValuePropertySource {name='random'}, OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.properties]'}]}"
"spring.servlet.multipart-org.springframework.boot.autoconfigure.web.servlet.MultipartProperties" -> {MultipartProperties@6137} 
"org.springframework.context.annotation.internalCommonAnnotationProcessor" -> {CommonAnnotationBeanPostProcessor@6138} 
"org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat" -> {ServletWebServerFactoryConfiguration$EmbeddedTomcat@6140} 
"spring.http-org.springframework.boot.autoconfigure.http.HttpProperties" -> {HttpProperties@6142} 
"springBootLoggingSystem" -> {LogbackLoggingSystem@6144} 
"org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration" -> {ErrorMvcAutoConfiguration@6146} 
"org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration$TomcatWebSocketConfiguration" -> {WebSocketServletAutoConfiguration$TomcatWebSocketConfiguration@6148} 
"org.springframework.boot.context.internalConfigurationPropertiesBinderFactory" -> {ConfigurationPropertiesBinder$Factory@6150} 
"servletContext" -> {ApplicationContextFacade@5736} 
"dispatcherServlet" -> {DispatcherServlet@6153} 
"org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration" -> {WebMvcAutoConfiguration@6155} 
"org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor" -> {ConfigurationPropertiesBindingPostProcessor@6156} 
"contextParameters" -> {Collections$UnmodifiableMap@6158}  size = 0
"systemProperties" -> {Properties@6160}  size = 67
"errorPageRegistrarBeanPostProcessor" -> {ErrorPageRegistrarBeanPostProcessor@6161} 
"errorPageCustomizer" -> {ErrorMvcAutoConfiguration$ErrorPageCustomizer@6163} 
"tomcatWebServerFactoryCustomizer" -> {TomcatWebServerFactoryCustomizer@6165} 
"springBootBanner" -> {SpringApplicationBannerPrinter$PrintedBanner@6167} 
"dispatcherServletRegistration" -> {DispatcherServletRegistrationBean@6169} "dispatcherServlet urls=[/]"
"tomcatServletWebServerFactory" -> {TomcatServletWebServerFactory@6171} 
"org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletConfiguration" -> {DispatcherServletAutoConfiguration$DispatcherServletConfiguration@6173} 
"messageSource" -> {DelegatingMessageSource@5032} "Empty MessageSource"
"helloFilter" -> {HelloFilter@6175} 
"springBootLoggerGroups" -> {LoggerGroups@6177} 

自动化配置:

  之前的启动结构图中,我们注意到无论是应用初始化还是具体的执行过程,都调用了SpringBoot自动配置模块

SpringBoot自动配置模块

 该配置模块的主要使用到了SpringFactoriesLoader,即Spring工厂加载器,该对象提供了loadFactoryNames方法,入参为factoryClass和classLoader,即需要传入上图中的工厂类名称和对应的类加载器,方法会根据指定的classLoader,加载该类加器搜索路径下的指定文件,即spring.factories文件,传入的工厂类为接口,而文件中对应的类则是接口的实现类,或最终作为实现类,所以文件中一般为如下图这种一对多的类名集合,获取到这些实现类的类名后,loadFactoryNames方法返回类名集合,方法调用方得到这些集合后,再通过反射获取这些类的类对象、构造方法,最终生成实例

工厂接口与其若干实现类接口名称

下图有助于我们形象理解自动配置流程

SpringBoot自动化配置关键组件关系图

 mybatis-spring-boot-starter、spring-boot-starter-web等组件的META-INF文件下均含有spring.factories文件,自动配置模块中,SpringFactoriesLoader收集到文件中的类全名并返回一个类全名的数组,返回的类全名通过反射被实例化,就形成了具体的工厂实例,工厂实例来生成组件具体需要的bean。

之前我们提到了EnableAutoConfiguration注解,其类图如下

可以发现其最终实现了ImportSelector(选择器)和BeanClassLoaderAware(bean类加载器中间件),重点关注一下AutoConfigurationImportSelector#selectImports()方法

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
      return NO_IMPORTS;
    }
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
        .loadMetadata(this.beanClassLoader);
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
        annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
  }

该方法在springboot启动流程——bean实例化前被执行,返回要实例化的类信息列表。我们知道,如果获取到类信息,spring自然可以通过类加载器将类加载到jvm中,现在我们已经通过spring-boot的starter依赖方式依赖了我们需要的组件,那么这些组建的类信息在select方法中也是可以被获取到的,不要急我们继续向下分析

目录
相关文章
|
19天前
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
98 0
|
27天前
|
前端开发 Java 数据安全/隐私保护
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
文章通过一个简单的SpringBoot项目,详细介绍了前后端如何实现用户登录功能,包括前端登录页面的创建、后端登录逻辑的处理、使用session验证用户身份以及获取已登录用户信息的方法。
112 2
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
|
19天前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
98 2
|
24天前
|
JavaScript 前端开发 开发者
Vue执行流程及渲染解析
【10月更文挑战第2天】
|
19天前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
21 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
20天前
|
JavaScript 前端开发 UED
Vue执行流程及渲染解析
【10月更文挑战第5天】
|
23天前
|
存储 搜索推荐 数据库
运用LangChain赋能企业规章制度制定:深入解析Retrieval-Augmented Generation(RAG)技术如何革新内部管理文件起草流程,实现高效合规与个性化定制的完美结合——实战指南与代码示例全面呈现
【10月更文挑战第3天】构建公司规章制度时,需融合业务实际与管理理论,制定合规且促发展的规则体系。尤其在数字化转型背景下,利用LangChain框架中的RAG技术,可提升规章制定效率与质量。通过Chroma向量数据库存储规章制度文本,并使用OpenAI Embeddings处理文本向量化,将现有文档转换后插入数据库。基于此,构建RAG生成器,根据输入问题检索信息并生成规章制度草案,加快更新速度并确保内容准确,灵活应对法律与业务变化,提高管理效率。此方法结合了先进的人工智能技术,展现了未来规章制度制定的新方向。
24 3
|
24天前
|
存储 缓存 边缘计算
揭秘直播带货背后的黑科技:播放流程全解析!
大家好,我是小米,今天聊聊社区直播带货的技术细节。我们将探讨直播播放流程中的关键技术,包括 HTTP DASH 协议、POP(Point of Presence)缓存和一致性哈希算法等。通过这些技术,直播流能根据网络状况动态调整清晰度,保证流畅体验。POP 和 DC 的多层次缓存设计减少了延迟,提升了观看效果。无论是技术人员还是直播运营者,都能从中受益。希望通过本文,你能更好地理解直播背后的技术原理。
37 3
|
24天前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
113 2
|
1月前
|
程序员 C++
C++编程:While与For循环的流程控制全解析
总结而言,`while`循环和 `for`循环各有千秋,它们在C++编程中扮演着重要的角色。选择哪一种循环结构应根据具体的应用场景、循环逻辑的复杂性以及个人的编程风格偏好来决定。理解这些循环结构的内在机制和它们之间的差异,对于编写高效、易于维护的代码至关重要。
35 1

推荐镜像

更多