SpringBoot 源码剖析
2021-05-16 14:54:18 91 举报
SpringBoot 启动和自动装配原理和源码解析
作者其他创作
大纲/内容
new DefaultApplicationArguments(args);
调用selectImports()
开启自动配置功能
prepareWebApplicationContext(servletContext);
1. 初始化SpringApplicationnew SpringApplication(primarySources)
MANIFEST.MF文件内容:Manifest-Version: 1.0Spring-Boot-Classpath-Index: BOOT-INF/classpath.idxImplementation-Title: lampImplementation-Version: 0.0.1-SNAPSHOTStart-Class: cn.xlysky.lamp.LampApplicationSpring-Boot-Classes: BOOT-INF/classes/Spring-Boot-Lib: BOOT-INF/lib/Build-Jdk-Spec: 1.8Spring-Boot-Version: 2.3.5.RELEASECreated-By: Maven Jar Plugin 3.2.0Main-Class: org.springframework.boot.loader.JarLauncherSpringBoot启动流程:(1)Spring Boot应用打包之后,生成一个Fat jar,包含了应用依赖的jar包和Spring Boot loader相关的类。 (2)Fat jar的启动Main函数是JarLauncher,它负责创建一个LaunchedURLClassLoader来加载/lib下面的jar,并以一 个新线程启动应用的Main函数。 JarLauncher通过加载BOOT-INF/classes目录及BOOT-INF/lib目录下jar文件,实现了fat jar的启动。 SpringBoot通过扩展JarFile、JarURLConnection及URLStreamHandler,实现了jar in jar中资源的加载。 SpringBoot通过扩展URLClassLoader–LauncherURLClassLoader,实现了jar in jar中class文件的加载。
printBanner(environment);
AbstractDispatcherServletInitializer
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId></plugin>
读取配置前发送ApplicationContextInitializedEvent
@SpringBootApplication
SpringBoot java -jar启动原理
beans.onStartup(servletContext);
利用多播器传播事件
注解
spring.factorties中获取所有key:org.springframework.context.ApplicationListener
如果没有的话获取ServletWebServerFactory
spring.factorties中获取所有key:org.springframework.context.ApplicationContextInitializer
启动后,反射运行指定类的main方法
refresh((ConfigurableApplicationContext)applicationContext)
listeners.environmentPrepared((ConfigurableEnvironment)environment);
容器会自动在classpath中找到 WebApplicationInitializer,并且传入到onStartup方法中
listeners.contextPrepared(context);
SpringBoot 自动装配
在spring.factroies中读取了SpringApplicationRunListener 的组件, 用来发布事件或者运行监听器
initialize();
getSpringFactoriesInstances(ApplicationListener.class)
Start-Class
getSpringFactoriesInstances(ApplicationContextInitializer.class)
继承关系
找到jar下的MANIFEST文件
控制台打印启动标记
getAutoConfigurationEntry(annotationMetadata);
@Import
onRefresh()
@HandlesTypes({WebApplicationInitializer.class})
更新PropertySources
外部引入Tomcat
ImportSelector
获取需要装配的key值EnableAutoConfiguration.class
AutoConfigurationImportSelector
main方法
pom文件
创建servlet容器根据不同的web调用不同类实现
将启动类作为配置类放入primarySourcesnew LinkedHashSet(Arrays.asList(primarySources));
springbootdemo-0.0.1-SNAPSHOT.jar
getServletContext();
getServletContextInitializerBeans()
2. 启动run(args)
run(args)传入的参数在这里实例化
ConfigurationPropertySources.attach(environment);
createRootApplicationContext(servletContext)
重要的一个导入类,具有延迟加载和分组的特性
生成一个jar包
getSelfInitializer()
SpringBootServletInitializer
每个springboot应用,都需要spring-boot-autoconfigure来自动装配,扫描META-INF/spring.factories,真正使自动配置生效的key是 org.springframework.boot.autoconfigure.EnableAutoConfiguration@Conditional派生注解(Spring注解版原生的@Conditional作用) 作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;@ConditionalOnJava 系统的java版本是否符合要求 @ConditionalOnBean 容器中存在指定Bean; @ConditionalOnMissingBean 容器中不存在指定Bean; @ConditionalOnExpression 满足SpEL表达式指定 @ConditionalOnClass 系统中有指定的类 @ConditionalOnMissingClass 系统中没有指定的类 @ConditionalOnSingleCandidate 容器中只有一个指定的Bean,或者这个Bean是首选Bean @ConditionalOnProperty 系统中指定的属性是否有指定的值 @ConditionalOnResource 类路径下是否存在指定资源文件@ConditionalOnWebApplication 当前是web环境 @ConditionalOnNotWebApplication 当前不是web环境 @ConditionalOnJndi JNDI存在指定项启用 debug=true属性;来让控制台打印自动配置报告
获取servlet上下文
builder.sources(Application.class)
拿到之前读取到所有ApplicationContextInitializer的组件 循环调用initialize方法
4. 创建Spring上下文
createApplicationContext();
加载配置
TomcatStartSpringBoot
tomcat.start();
启动
WebApplicationInitializer
得到内嵌tomcat
factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
this.createWebServer();
3. 读取环境变量读取配置文件信息(基于监听器)参数也在这里真正使用
this.getSpringFactoriesLoaderFactoryClass()
refreshContext(context);
创建application上下文
设置servlet上下文
getWebServerFactory();
ContextLoaderListener 和DispatcherServlet由AbstractContextLoaderInitializer和AbstractDispatcherServletInitializer来创建
this.getRunListeners(args);
(new SpringApplication(primarySources)).run(args);
startDaemonAwaitThread
发布ApplicationStartingEvent事件在运行开始时发送
listeners.starting();
读取完配置类后发送ApplicationPreparedEvent
读取了全局配置文件
org.springframework.web.SpringServletContainerInitializer
Main-Class指定启动类
扫描META-INF/spring.factories
this.mainApplicationClass = deduceMainApplicationClass();
AbstractContextLoaderInitializer
在启动的过程中,有很多监听器被调用:1. 开始运行时starting()2. 读取全局配置时environmentPrepared()3. spring上下文加载前initialize()4. Spring上下文加载完成后loaded()
ServletContextInitializer有一个OnStartUp()启动Debug下,可以看见里面有DispatcherServlet这个类,在springboot中,注册Servlet需要通过ServletRegistrationBean,并且通过DispatcherServletAutoConfiguration注入,
6. 加载IOC容器
加载自动配置类:invokeBeanFactoryPostProcessors , 创建servlet容器onRefresh
applyInitializers(context);
stopWatch.stop();
取所有servlet组件
5. 预初始化spring上下文
内嵌tomat
去META-INF/services 文件夹中找到javax.servlet.ServletContainerInitializer
防止启动完就关闭tomcat.getServer.await();
@EnableAutoConfiguration
开始监控运行时间stopWatch.start();
DeferredImportSelector
利用SPI机制
根据传入的Springboot启动类来构建一个SpringApplication
configure(builder);
根据main方法推算出mainApplicationClass
listeners.contextLoaded(context);
启动springboot应用
run(application);
0 条评论
下一页