Springboot启动流程分析
目录
- 先简单介绍一些SpringBoot 组件
- 介绍启动流程
参考资料
- 下面这篇文章是有关springboot使用自定义properties配置文件的信息
参考文字:在SpringBoot下读取自定义properties配置文件的方法 - Spring Boot启动流程详解(一)
- SpringBoot启动分析之getSpringFactoriesInstances
- 参考视频:springboot底层原理33集后开始食用
- Spring Boot启动过程完全解析
- 一般都用ApplicantContext代替BeanFactory
@SpringBootConfiguration的介绍
首先介绍以下@SpringbootConfiguration的作用
- 源码内含@Configuration ,也就是用@SpringbootConfiguration 的类就可以当配置类,如main方法也可以作为配置类 【可以参考 注解@SpringbootConfiguration 的源码】
- @SpringbootConfiguration会将当前类内声明的一个或多个用@Bean注解标记的方法的实例放到入到spring容器IOC中,并且实例名就是方法名。
接下来 通过springboot的启动,我们用代码的运行结果来说明上面的情况
代码1 是Springboot启动类 也充当配置类
@SpringBootApplication public class SpringbootdemoApplication { public static void main(String[] args) { //在这里标明以下SpringApplication.run方法返回的是spring的IOC容器 //ConfigurableApplicationContext 跟ClassPathXmlApplicationContext都是ApplicationContext实现类 ConfigurableApplicationContext applicationContext = SpringApplication.run(SpringbootdemoApplication.class, args); System.out.println(applicationContext.getBean("getPerson")); System.out.println(applicationContext.getBean("student")); } @Bean public Person getPerson() { return new Person(); } public static class Person { } //Person类 }
代码2 自己写的配置类
@Configuration //同样Configuration也可以改为SpringBootApplication public class MyConfig { @Bean public Student student(){ return new Student(); } public static class Student{}//Student类 }
效果 两个类都放到了IOC容器中
springboot启动类的run真正的是
- 代码
SpringApplication.run(SpringbootdemoApplication.class, args); || 进入run方法 \/ public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { return run(new Class[]{primarySource}, args); } || 再次进入run方法 \/ public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); } || \/ 再次进入的run方法是下面的ConfigurableApplicationContext 请继续看
这时候可以知道springboot基本的启动流程
创建new SpringApplication
调用run方法 .run
也就是运行下面这一堆 这一堆也是springboot运行的底层启动流程代码 后面会更详细介绍
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start();//里面的代码实际就是System.currentTimeMillis();用来计时启动事件 ConfigurableApplicationContext context = null; //IOC容器 //exceptionReporters 异常的报告器 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); //Banner 也就是spring的广告图 我们可以换成其他一些好玩的 Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop();//跟上面的start对应 计时器 if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
SpringApplication的初始化过程
代码 做初始化
//构造函数 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.sources = new LinkedHashSet(); this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; this.addCommandLineProperties = true; this.addConversionService = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = new HashSet(); this.isCustomEnvironment = false; this.lazyInitialization = false; this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); //重点 // primarySources 接收启动器的args参数 this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); }
WebApplicationType : 一般是得到SERVLET WebApplicationType应用类型
可以干嘛呢? 我们可以通过配置来设置是否使用Springboot内置的tomcat
如:
web-application-type:none 为none时 需要配置外部Tomcat执行
为servlet时 用的是自身的Tomcatstatic WebApplicationType deduceFromClasspath() { //下面是判断有没有对应的类 响应式编程需要webflux包 暂时没有 //isPresent的底层是用反射来生成传入的字符串 然后看看那些类必须有 那些类不能有 if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) { return REACTIVE;//reactive : spring5的新特性 代表是否用响应式编程 } else { //到了else 说明含有DispatcherServlet String[] var0 = SERVLET_INDICATOR_CLASSES;//SERVLET_INDICATOR_CLASSES的值看下面 // private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"}; 查找又没有后面的类 有的√ //找出DispatchServlet int var1 = var0.length; //遍历我们需要的类SERVLET_INDICATOR_CLASSES是否存在 不存在return NONE for(int var2 = 0; var2 < var1; ++var2) { String className = var0[var2]; if (!ClassUtils.isPresent(className, (ClassLoader)null)) { return NONE; } } return SERVLET; } }
setInitializers 对容器一些初始化配置
运行 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); 其中getSpringFactoriesInstances的底层是 SpringFactoriesLoader 【去找META-INF/spring.factories】 this.getSpringFactoriesInstances(ApplicationContextInitializer.class)中的 ApplicationContextInitializer在以下找 META-INF/spring.factories文件对应的内容为 # Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer //在springApplication中有SpringFactoriesLoader.loadFactoryNames //利用其去.properties文件中进行查找 【基本的配置文件♥】 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = this.getClassLoader(); Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; } || \/ SpringFactoriesLoader.loadFactoryNames(type, classLoader)的具体方法 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); }
setListeners:
- mainApplicationClass:启动类
springbootApplication注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { }
注解包装了SpringBootConfiguration【包含了Configuration 类似xml】、EnableAutoConfiguration、ComponentScan【default "*/.class" 当前文件路径会自动被扫描】
- EnableAutoConfiguration的作用【auto配置文件 ♥】 -->DispatcherServlet(springmvc)
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {}
遍历所有的Auto配置文件里面的组件(如果一些没法添加 后来就没有加入IOC中)
springboot如何加载tomcat 和springmvc
tomcat
- 从配置取出的类 已经是加载到了ioc中 该类通过ctrl+alt+shift+N找的 会加到springboot里面
含有三个服务器的配置文件 @Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class }) public class ServletWebServerFactoryAutoConfiguration { @Bean public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) { return new ServletWebServerFactoryCustomizer(serverProperties); }//注意后面的serverProperties }
ctrl + K 得知是开启tomcat
下面的类会读取自己写的yaml配置 @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties { /** * Server HTTP port. */ private Integer port; }
在tomcat工厂中是实现了new Tomcat(); 后面设置tomcat 然后启动mvc
DispatcherServletAutoConfiguration
配置
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass(DispatcherServlet.class)//DispatcherServlet注入ioc中 @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration { public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet"; public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration"; @Configuration(proxyBeanMethods = false) @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) @EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class }) protected static class DispatcherServletConfiguration { @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) { ... return dispatcherServlet; }
自定义的配置
@ConfigurationProperties(prefix = "spring.mvc") public class WebMvcProperties { private Locale locale; }
启动流程
SpringApplication -> run - > ConfigurableApplicationContext
博客运行流程
代码同上面的
下面也是SpringApplication的run方法 public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start();//实际就是System.currentTimeMillis() ConfigurableApplicationContext context = null; //IOC容器 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();//记录错误日志 this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); //Banner 也就是spring的广告图 我们可以换成其他一些好玩的 Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop();//跟上面的start对应 计时器 if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
- 自定义外部扩展文件
利用底层的源代码 将my.properties放入springboot
总结启动流程
创建springApplication 对象 new SpringApplication ,Springboot容器初始化操作
获取当前应用启动类型 原理:判断classpath是否有加载我们的servlet类 返回servlet web启动方式
this.webApplicationType = WebApplicationType.deduceFromClasspath(); 类型:REACTIVE NONE SERVLET
setInitializers:读取SpringBoot包下面的META-INF/spring.factories 获取对应的ApplicationContextInitializer装配到集合中
setListeners :读取SpringBoot包下面的META-INF/spring.factories 获取对应的ApplicationContextListener装配到集合中
mainApplicationClass获取当前运行的主函数
调用springApplication的 run方法 也就是上面的方法ConfigurableApplicationContext run 实现启动
StopWatch stopWatch = new StopWatch();记录我们springboot项目启动时间
运行下面的代码 getRunListeners读取我们的META-INF/spring.factories文件 如SpringApplicationRunListener
SpringApplicationRunListeners listeners = this.getRunListeners(args); || \/ private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class[]{SpringApplication.class, String[].class}; return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); } || \/ getSpringFactoriesInstances :读取spring.factories文件 || \/ this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = this.getClassLoader(); Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; } 上面的代码经过核对跟上面获取 setInitializers setListeners 一致 但是获取到的结果不应用 找的方式相同 上面返回的SpringApplicationRunListener类 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); 其中的SpringFactoriesLoader到"META-INF/spring.factories"下找配置文件的内容 找到了 spring.factories下的 org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener
EventPublishingRunListener:作用是给我们springboot配置文件(application.yaml...)进行赋值 参数文件配置到容器中listeners.starting(); 循环调用start方法
void starting() { //所有的***进行启动 Iterator var1 = this.listeners.iterator(); while(var1.hasNext()) { SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next(); listener.starting(); } } 在EventPublishingRunListener的start方法 public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); }
先插入讲一个运用场景
自定义一个类SpringApplicationRunListener文件路径--->main\resources\META-INF\spring.factories: org.springframework.boot.SpringApplicationRunListener=\ com.project.springbootdemo.MySpringBootApplicationRunListener //仿造 EventPublishingRunListener来编写代码 public class MySpringBootApplicationRunListener implements SpringApplicationRunListener { //application、args、MySpringBootApplicationRunListener:必备的代码 private final SpringApplication application; private final String[] args; public MySpringBootApplicationRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; } @Override public void starting() { System.out.println("---->>>starting"); } //配置文件读取到程序中,需要自己将本地文件读取到程序中,然后再放入spring容器 @Override public void environmentPrepared(ConfigurableEnvironment environment) {//environment是springboot提供的 System.out.println("---->>>environmentPrepared"); Properties properties = new Properties(); try { //读取我们的配置文件 properties.load(getClass().getClassLoader().getResourceAsStream("my.properties")); //读取名称 PropertySource propertySource = new PropertiesPropertySource("person.name", properties); //将资源添加到Springboot项目中 //取出environment的getPropertySources MutablePropertySources propertySources = environment.getPropertySources(); // 通过该api接口可以将配置文件读取到springboot项目中 propertySources.addLast(propertySource); System.out.println(propertySources.size()); } catch (IOException e) { e.printStackTrace(); } } @Override public void contextPrepared(ConfigurableApplicationContext context) { System.out.println("---->>>contextPrepared"); } @Override public void contextLoaded(ConfigurableApplicationContext context) { System.out.println("---->>>contextLoaded"); } @Override public void started(ConfigurableApplicationContext context) { System.out.println("---->>>started"); } }
记载成功
读取成功@RestController public class TestController { @Value("${person.name}") //从environment里面取 private String value; @RequestMapping("/hello") public String hello(Map<String,Object>map){ return value; } }
参数赋值
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); || \/ private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // 运行***environmentPrepared 读取配置文件到springboot容器中 参考我们写的MySpringBootApplicationRunListener listeners.environmentPrepared((ConfigurableEnvironment)environment); } || \/ void environmentPrepared(ConfigurableEnvironment environment) { Iterator var2 = this.listeners.iterator(); while(var2.hasNext()) { SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next(); //下面的方法是重点 我们重点研究EventPublishingRunListener listener.environmentPrepared(environment); } } || \/ 进入EventPublishingRunListener public void environmentPrepared(ConfigurableEnvironment environment) { this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment)); } || \/ public void multicastEvent(ApplicationEvent event) { this.multicastEvent(event, this.resolveDefaultEventType(event)); } || \/ public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event); Executor executor = this.getTaskExecutor(); Iterator var5 = this.getApplicationListeners(event, type).iterator(); while(var5.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var5.next(); if (executor != null) { executor.execute(() -> { this.invokeListener(listener, event); }); } else { 运行------> this.invokeListener(listener, event); } } } || \/ protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) { ErrorHandler errorHandler = this.getErrorHandler(); if (errorHandler != null) { try { this.doInvokeListener(listener, event); } catch (Throwable var5) { errorHandler.handleError(var5); } } else { 运行-----> this.doInvokeListener(listener, event); } } || \/ private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { 运行 ---> listener.onApplicationEvent(event);//有很多事件 } catch (ClassCastException var6) { String msg = var6.getMessage(); if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) { throw var6; } Log logger = LogFactory.getLog(this.getClass()); if (logger.isTraceEnabled()) { logger.trace("Non-matching event type for listener: " + listener, var6); } } } listener.onApplicationEvent(event);EventPublishingRunListener找的是ConfigFileApplicationListener 去默认配置的路径找 "classpath:/,classpath:/config/,file:./,file:./config/"; || \/ public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationEnvironmentPreparedEvent) { 运行---->this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event); } if (event instanceof ApplicationPreparedEvent) { this.onApplicationPreparedEvent(event); } } || \/ private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) { List<EnvironmentPostProcessor> postProcessors = this.loadPostProcessors(); postProcessors.add(this); AnnotationAwareOrderComparator.sort(postProcessors); Iterator var3 = postProcessors.iterator(); while(var3.hasNext()) { EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var3.next(); 运行--->postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());//找到的是ConfigFileApplicationListener*** } } || \/ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { this.addPropertySources(environment, application.getResourceLoader()); } || \/ protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { RandomValuePropertySource.addToEnvironment(environment); (new ConfigFileApplicationListener.Loader(environment, resourceLoader)).load(); //Loader类读取一些配置文件 重点看load方法 } || \/ public void load(){} || \/ private void load(ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) { this.getSearchLocations().forEach((location) -> { boolean isFolder = location.endsWith("/"); Set<String> names = isFolder ? this.getSearchNames() : ConfigFileApplicationListener.NO_SEARCH_NAMES; for循环 names.forEach((name) -> { --> this.load(location, name, profile, filterFactory, consumer); }); }); } || \/ 所有的配置路径会遍历一遍 除非找到目标文件 private void load(String location, String name, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) { if (!StringUtils.hasText(name)) { Iterator var13 = this.propertySourceLoaders.iterator(); PropertySourceLoader loader; do { if (!var13.hasNext()) { throw new IllegalStateException("File extension of config file location '" + location + "' is not known to any PropertySourceLoader. If the location is meant to reference a directory, it must end in '/'"); } loader = (PropertySourceLoader)var13.next(); } while(!this.canLoadFileExtension(loader, location)); this.load(loader, location, profile, filterFactory.getDocumentFilter(profile), consumer); } else { Set<String> processed = new HashSet(); Iterator var7 = this.propertySourceLoaders.iterator(); // PropertySourceLoader 分析得到他的继承类有两个properties yaml 其中子类实现的文件后缀有 properties xml yaml yml while(var7.hasNext()) { PropertySourceLoader loaderx = (PropertySourceLoader)var7.next(); String[] var9 = loaderx.getFileExtensions(); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String fileExtension = var9[var11]; if (processed.add(fileExtension)) { this.loadForFileExtension(loaderx, location + name, "." + fileExtension, profile, filterFactory, consumer); } } } } } || \/ private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilterFactory filterFactory, ConfigFileApplicationListener.DocumentConsumer consumer) { this.load(loader, prefix + fileExtension, profile, profileFilter, consumer); } || \/ private void load(PropertySourceLoader loader, String location, ConfigFileApplicationListener.Profile profile, ConfigFileApplicationListener.DocumentFilter filter, ConfigFileApplicationListener.DocumentConsumer consumer) { try { Resource resource = this.resourceLoader.getResource(location); else { String name = "applicationConfig: [" + location + "]"; ---->List<ConfigFileApplicationListener.Document> documents = this.loadDocuments(loader, name, resource); if (CollectionUtils.isEmpty(documents)) { if (this.logger.isTraceEnabled()) { StringBuilder description = this.getDescription("Skipped unloaded config ", location, resource, profile); this.logger.trace(description); } } ... } || \/ 读取加载成功后 通过 this.addLoadedPropertySources();将文件记载到springboot中 如environment private void addLoadedPropertySources() { MutablePropertySources destination = this.environment.getPropertySources(); List<MutablePropertySources> loaded = new ArrayList(this.loaded.values()); Collections.reverse(loaded); String lastAdded = null; Set<String> added = new HashSet(); Iterator var5 = loaded.iterator(); .... }
去默认配置文件路径下找 file【直接编译前的配置文件】 classpath【读取编译后的配置文件】 默认读取application
PropertySourceLoader 分析得到他的实现类有两个properties yaml 其中子类实现的文件后缀有 properties xml yaml yml每一种都会读取以下
最后在对应的路径下找到了 然后在PropertySourceLoader 的实现类中解析
读取会覆盖 Order制定优先级(Event*** )
读取顺序properties xml yml yaml打印springboot Banner图
context = this.createApplicationContext(); 初始化AnnotationConfigServletWebServerApplicationContext(IOC)
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch(this.webApplicationType) { case SERVLET: ---> contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"); break; } } catch (ClassNotFoundException var3) { throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3); } }
先做一些的提前准备 然后执行this.refreshContext(context);刷新上下文
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); || \/ private void refreshContext(ConfigurableApplicationContext context) { this.refresh(context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException var3) { } } } || \/ protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext)applicationContext).refresh(); -->选择到ServletWebServerApplicationContext } || \/ public final void refresh() throws BeansException, IllegalStateException { try { super.refresh(); springioc的创建方法 } catch (RuntimeException var2) { this.stopAndReleaseWebServer(); throw var2; } } || \/ super.refresh 中有一个 this.OnRefresh() || \/ this.createWebServer(); || \/ private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = this.getServletContext(); if (webServer == null && servletContext == null) { ServletWebServerFactory factory = this.getWebServerFactory(); //获得tomcat this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()}); } }
创建tomcat
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, ---->ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class }) public class ServletWebServerFactoryAutoConfiguration { ... } || \/ static class EmbeddedTomcat { @Bean ---> TomcatServletWebServerFactory tomcatServletWebServerFactory( ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers, ObjectProvider<TomcatContextCustomizer> contextCustomizers, ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.getTomcatConnectorCustomizers() .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatContextCustomizers() .addAll(contextCustomizers.orderedStream().collect(Collectors.toList())); factory.getTomcatProtocolHandlerCustomizers() .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList())); return factory; } || \/ TomcatServletWebServerFactory public WebServer getWebServer(ServletContextInitializer... initializers) { Tomcat tomcat = new Tomcat(); }
开始加载springmvc
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE) @Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass(DispatcherServlet.class) @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) public class DispatcherServletAutoConfiguration { @Configuration(proxyBeanMethods = false) @Conditional(DefaultDispatcherServletCondition.class) @ConditionalOnClass(ServletRegistration.class) @EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class }) protected static class DispatcherServletConfiguration { ---> @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) { DispatcherServlet dispatcherServlet = new DispatcherServlet(); dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest()); dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest()); dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound()); dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents()); dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails()); return dispatcherServlet; } }
- 定义afterRefresh 是一个空方法
让用户自定义编写protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) { }
- 调用started 告诉别人***启动成功
- listener.running()