SpringBoot启动流程解析

简介: 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方法中也是可以被获取到的,不要急我们继续向下分析

目录
相关文章
|
9月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
2844 0
|
8月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
8月前
|
XML JSON Java
【SpringBoot(三)】从请求到响应再到视图解析与模板引擎,本文带你领悟SpringBoot请求接收全流程!
Springboot专栏第三章,从请求的接收到视图解析,再到thymeleaf模板引擎的使用! 本文带你领悟SpringBoot请求接收到渲染的使用全流程!
571 3
|
9月前
|
Java 数据库 数据安全/隐私保护
Spring Boot四层架构深度解析
本文详解Spring Boot四层架构(Controller-Service-DAO-Database)的核心思想与实战应用,涵盖职责划分、代码结构、依赖注入、事务管理及常见问题解决方案,助力构建高内聚、低耦合的企业级应用。
1646 1
|
9月前
|
存储 域名解析 弹性计算
阿里云上云流程参考:云服务器+域名+备案+域名解析绑定,全流程图文详解
对于初次通过阿里云完成上云的企业和个人用户来说,很多用户不仅是需要选购云服务器,同时还需要注册域名以及完成备案和域名的解析相关流程,从而实现网站的上线。本文将以上云操作流程为核心,结合阿里云的活动政策与用户系统梳理云服务器选购、域名注册、备案申请及域名绑定四大关键环节,以供用户完成线上业务部署做出参考。
|
11月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
11月前
|
机器学习/深度学习 XML Java
【spring boot logback】日志logback格式解析
在 Spring Boot 中,Logback 是默认的日志框架,它支持灵活的日志格式配置。通过配置 logback.xml 文件,可以定义日志的输出格式、日志级别、日志文件路径等。
1887 5
|
11月前
|
Java 关系型数据库 数据库连接
Spring Boot项目集成MyBatis Plus操作PostgreSQL全解析
集成 Spring Boot、PostgreSQL 和 MyBatis Plus 的步骤与 MyBatis 类似,只不过在 MyBatis Plus 中提供了更多的便利功能,如自动生成 SQL、分页查询、Wrapper 查询等。
1019 2
|
12月前
|
Java 数据库连接 API
Java 对象模型现代化实践 基于 Spring Boot 与 MyBatis Plus 的实现方案深度解析
本文介绍了基于Spring Boot与MyBatis-Plus的Java对象模型现代化实践方案。采用Spring Boot 3.1.2作为基础框架,结合MyBatis-Plus 3.5.3.1进行数据访问层实现,使用Lombok简化PO对象,MapStruct处理对象转换。文章详细讲解了数据库设计、PO对象实现、DAO层构建、业务逻辑封装以及DTO/VO转换等核心环节,提供了一个完整的现代化Java对象模型实现案例。通过分层设计和对象转换,实现了业务逻辑与数据访问的解耦,提高了代码的可维护性和扩展性。
455 1

热门文章

最新文章

推荐镜像

更多
  • DNS