spring整套源码系列之【springboot启动流程源码分析】
2024-04-10 18:47:25 2 举报
spring整套源码系列之【springboot启动流程源码分析】
作者其他创作
大纲/内容
入口
invokeProtocolHandlerCustomizers(connector.getProtocolHandler())
添加映射registration.addMapping(getServletMappings());
拿到之前读取到所有ApplicationContextInitializer的组件, 循环调用initialize方法 applyInitializers(context);
AbstractDispatcherServletInitializer
继续循环
run(args)
使用一个线程去挂起tomcatstartDaemonAwaitThread();
去spring.factroies中读取了SpringApplicationRunListener 的组件, 就是用来发布事件或者运行监听器 SpringApplicationRunListeners listeners = getRunListeners(args);
就是判断当前是否存在某个类,比如存在DispatcherServlet说明为servlet环境
回调函数接口,这里调用链很深,调试知道调用了过来
如果springboot项目想运行在外部tomcat需要实现一个SpringBootServletInitializer
设置tomcat的连接者tomcat.setConnector(connector);
拿到直接启动getSelfInitializer().onStartup(servletContext);
首次去读取到spring.factories数据放入缓存,后续就不需要读文件了直接拿就行了
initPropertySources();
看到这个为什么能取到?自然就去想到自动装配,所以我们去找下servlet的自动装配
区分外置跟内嵌tomcat的webServer == null && servletContext == null
去spring.factories 中去获取所有key为Bootstrapper的this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
创建tomcat服务器对象Tomcat tomcat = new Tomcat();
getSelfInitializer()
自动装配而来
创建tomcat启动者TomcatStarter starter = new TomcatStarter(initializers)
取得ServletWebServerFactory类型的bean定义名称String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
自动装配ServletWebServerFactoryAutoConfiguration
开启tomcat服务并返回return getTomcatWebServer(tomcat);
beans.onStartup(servletContext);
完成了tomcat的启动onRefresh#AnnotationConfigServletWebServerApplicationContext
通过spi去META-INF/services文件夹中找到javax.servlet.ServletContainerInitializer对应的实现类SpringServletContainerInitializer,然后实例化
发布了ApplicationContextInitializedEvent listeners.contextPrepared(context);
忽略beaninfo的bean configureIgnoreBeanInfo(environment);
外置tomcat启动spring-boot
初始化servlet容器,设置servlet的地方selfInitialize()
for循环
new SpringApplication(primarySources)
tomcat启动
创建tomcatWeb服务器this.webServer = factory.getWebServer(getSelfInitializer());
声明@HandlesTypes后tomcat会主动帮忙我们找到所有的WebApplicationInitializer类型的类传入onStartup方法中调用,其中有两个最重要的:1:我们自己实现的类(用来找到springboot启动类)2:AbstractDispatcherServletInitializer(用来创建DispatcherServlet)
不存在,内嵌tomcat
ConfigFileApplicationListener会读取所有默认配置文件信息* <ul> * <li>file:./config/</li> * <li>file:./config/{@literal *}/</li> * <li>file:./</li> * <li>classpath:config/</li> * <li>classpath:</li> * </ul>
读取完配置类后发送ApplicationPreparedEvent。 listeners.contextLoaded(context)
合并servlet上下文初始化回调函数ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
拿到servlet容器上下文Context context = findContext();
我们在java-jar中也能指定一些参数,比如端口啊,就是在这获取到的,说白了就是main方法中的args参数
预初始化web应用上下文prepareWebApplicationContext(servletContext)
内嵌tomcat添加DispatcherServlet
创建内嵌tomcat上下文对象TomcatEmbeddedContext context = new TomcatEmbeddedContext();
加载spring ioc 容器 **相当重要 由于是使用AnnotationConfigServletWebServerApplicationContext 启动的spring容器所以springboot对它做了扩展:
自动装配DispatcherServlet
循环调用WebApplicationInitializer的onStartup方法for (WebApplicationInitializer initializer : initializers)
TomcatWebServer.this.tomcat.getServer().await();
创建nio协议连接者Connector connector = new Connector(this.protocol);
将@PropertieSource的配置信息 放在第一位, 因为读取配置文件@PropertieSource优先级是最低的 ConfigurationPropertySources.attach(environment);
循环处理定制for(TomcatContextCustomizer customizer : this.tomcatContextCustomizers)
创建web服务器createWebServer();
存在,外置tomcat
启动springboot,跟我们启动springboot一样application.run()
将配置类(主类)赋值到对象属性中this.resourceLoader = resourceLoader;
启动tomcatthis.tomcat.start();
创建DispatcherServletFrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
注册了一个DispatcherServletregisterDispatcherServlet(servletContext);
将启动类放入primarySources this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
根据传入的Springboot启动类来构建一个SpringApplication SpringApplication application = builder.build();
如果是外置tomcat则不为空ServletContext servletContext = getServletContext();
return
createRootApplicationContext(servletContext);
这里会拿到自动装配到的DispatcherServlet对象,也就是springmvc关键的那个getServletContextInitializerBeans()
根据webApplicationType创建Spring上下文 context = createApplicationContext();
refresh()#AnnotationConfigServletWebServerApplicationContext
将函数接口传入,并不会立马执行selfInitialize()方法,后面会回调return this::selfInitialize;
其他的方法跟spring一样,只看onRefresh方法
打印Banner 横幅(spring-boot那个标志) Banner printedBanner = printBanner(environment);
给上下文设置一些基本的属性
tomcat挂起
return run(application);
如果是外置tomcat则不为空WebServer webServer = this.webServer;
端口默认8080
// 用来记录当前springboot启动耗时 StopWatch stopWatch = new StopWatch(); // 就是记录了启动开始时间 stopWatch.start();
在2.4.4之后在ConfigDataEnvironmentPostProcessor读取
触发回调
发布ApplicationStartingEvent事件,在运行开始时发送 listeners.starting();
设置端口到connector中connector.setPort(port);
获取当前spring上下文beanFactory (负责创建bean) ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
return new SpringApplication(primarySources).run(args);
它是任何spring上下文的接口, 所以可以接收任何ApplicationContext实现 ConfigurableApplicationContext context = null;
从ioc容器中拿到web服务器工厂ServletWebServerFactory factory = getWebServerFactory();
初始化initialize();
onStartup(ServletContext servletContext)#SpringBootServletInitializer
ConfigurableApplicationContext为spring上下文的顶级接口
return this.applicationContextFactory.create(this.webApplicationType);
设置服务的连接者tomcat.getService().addConnector(connector);
发布了ApplicationEnvironmentPreparedEvent 的监听器 读取了全局配置文件 listeners.environmentPrepared(environment);
context.addLifecycleListener(new StaticResourceConfigurer(context));
这是个空方法postProcessContext(context);
这里就会添加springmvc关键的那个DispatcherServlet
外置tomcat添加DispatcherServlet
自动装配servlet服务器工厂
去spring.factories 中去获取所有key: org.springframework.context.ApplicationListener #setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
我们自己实现的SpringBootServletInitializer
创建临时tomcat文件夹File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir(\"tomcat\");
外置tomcat启动spring-boot的war包
定制连接者customizeConnector(connector);
自动装配DispatcherServletAutoConfiguration
for循环执行所有的ServletContextInitializerfor (ServletContextInitializer beans : getServletContextInitializerBeans())
将所有spring.main 开头的配置信息绑定SpringApplication bindToSpringApplication(environment)
SpringApplicationBuilder builder = createSpringApplicationBuilder();
根据main方法推算出mainApplicationClass,说白了就是设置mainApplicationClass为启动类的class对象 this.mainApplicationClass = deduceMainApplicationClass();
处理定制customizer.customize(context);
调用我们重写的方法,指明了springboot启动类builder = configure(builder)
加载自动配置类:invokeBeanFactoryPostProcessors , 创建servlet容器onRefresh,会调用到spring最重要的方法refresh()refreshContext(context);
registerApplicationScope(servletContext);
//更新PropertySources ConfigurationPropertySources.attach(environment);
去spring.factories 中去获取所有key:org.springframework.context.ApplicationContextInitializer #setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
configureSession(context)
根据webApplicationType 创建Environment 创建就会读取: java环境变量和系统环境变量 ConfigurableEnvironment environment = getOrCreateEnvironment();
根据命令行参数 实例化一个ApplicationArguments ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
开启了Headless模式: configureHeadlessProperty();
0 条评论
下一页