厉害了!SpringBoot是如何动起来的!
程序入口
springapplication.run(beautyapplication.class, args);
执行此方法来加载整个springboot的环境。
1. 从哪儿开始?
springapplication.java
/** * run the spring application, creating and refreshing a new * {@link applicationcontext}. * @param args the application arguments (usually passed from a java main method) * @return a running {@link applicationcontext} */ public configurableapplicationcontext run(string... args) { //... }
调用springapplication.java 中的 run 方法,目的是加载spring application,同时返回 applicationcontext。
2. 执行了什么?
2.1 计时
记录整个spring application的加载时间!
stopwatch stopwatch = new stopwatch(); stopwatch.start(); // ... stopwatch.stop(); if (this.logstartupinfo) { new startupinfologger(this.mainapplicationclass) .logstarted(getapplicationlog(), stopwatch); }
2.2 声明
// 声明 applicationcontext configurableapplicationcontext context = null; // 声明 一个异常报告集合 collection<springbootexceptionreporter> exceptionreporters = new arraylist<>();
2.3 指定程序运行模式
指定 java.awt.headless,默认是true 一般是在程序开始激活headless模式,告诉程序,现在你要工作在headless mode下,就不要指望硬件帮忙了,你得自力更生,依靠系统的计算能力模拟出这些特性来。
private void configureheadlessproperty() { system.setproperty(system_property_java_awt_headless, system.getproperty( system_property_java_awt_headless, boolean.tostring(this.headless))); }
2.4 配置监听并发布应用启动事件
springapplicationrunlistener 负责加载 applicationlistener事件。
springapplicationrunlisteners listeners = getrunlisteners(args); // 开始 listeners.starting(); // 处理所有 property sources 配置和 profiles 配置,准备环境,分为标准 servlet 环境和标准环境 configurableenvironment environment = prepareenvironment(listeners,applicationarguments); // 准备应用上下文 preparecontext(context, environment, listeners, applicationarguments,printedbanner); // 完成 listeners.started(context); // 异常 handlerunfailure(context, ex, exceptionreporters, listeners); // 执行 listeners.running(context);
getrunlisteners 中根据 type = springapplicationrunlistener.class 去拿到了所有的 listener 并根据优先级排序。
对应的就是 meta-inf/spring.factories 文件中的 org.springframework.boot.springapplicationrunlistener=org.springframework.boot.context.event.eventpublishingrunlistener
private <t> collection<t> getspringfactoriesinstances(class<t> type, class<?>[] parametertypes, object... args) { classloader classloader = thread.currentthread().getcontextclassloader(); // use names and ensure unique to protect against duplicates set<string> names = new linkedhashset<>( springfactoriesloader.loadfactorynames(type, classloader)); list<t> instances = createspringfactoriesinstances(type, parametertypes, classloader, args, names); annotationawareordercomparator.sort(instances); return instances; }
在 applicationlistener 中 , 可以针对任何一个阶段插入处理代码。
public interface springapplicationrunlistener { /** * called immediately when the run method has first started. can be used for very * early initialization. */ void starting(); /** * called once the environment has been prepared, but before the * {@link applicationcontext} has been created. * @param environment the environment */ void environmentprepared(configurableenvironment environment); /** * called once the {@link applicationcontext} has been created and prepared, but * before sources have been loaded. * @param context the application context */ void contextprepared(configurableapplicationcontext context); /** * called once the application context has been loaded but before it has been * refreshed. * @param context the application context */ void contextloaded(configurableapplicationcontext context); /** * the context has been refreshed and the application has started but * {@link commandlinerunner commandlinerunners} and {@link applicationrunner * applicationrunners} have not been called. * @param context the application context. * @since 2.0.0 */ void started(configurableapplicationcontext context); /** * called immediately before the run method finishes, when the application context has * been refreshed and all {@link commandlinerunner commandlinerunners} and * {@link applicationrunner applicationrunners} have been called. * @param context the application context. * @since 2.0.0 */ void running(configurableapplicationcontext context); /** * called when a failure occurs when running the application. * @param context the application context or {@code null} if a failure occurred before * the context was created * @param exception the failure * @since 2.0.0 */ void failed(configurableapplicationcontext context, throwable exception); }
3. 每个阶段执行的内容
3.1 listeners.starting();
在加载spring application之前执行,所有资源和环境未被加载。
3.2 prepareenvironment(listeners, applicationarguments);
创建 configurableenvironment;将配置的环境绑定到spring application中;
private configurableenvironment prepareenvironment( springapplicationrunlisteners listeners, applicationarguments applicationarguments) { // create and configure the environment configurableenvironment environment = getorcreateenvironment(); configureenvironment(environment, applicationarguments.getsourceargs()); listeners.environmentprepared(environment); bindtospringapplication(environment); if (this.webapplicationtype == webapplicationtype.none) { environment = new environmentconverter(getclassloader()) .converttostandardenvironmentifnecessary(environment); } configurationpropertysources.attach(environment); return environment; }
3.3 preparecontext
配置忽略的bean;
private void configureignorebeaninfo(configurableenvironment environment) { if (system.getproperty( cachedintrospectionresults.ignore_beaninfo_property_name) == null) { boolean ignore = environment.getproperty("spring.beaninfo.ignore", boolean.class, boolean.true); system.setproperty(cachedintrospectionresults.ignore_beaninfo_property_name, ignore.tostring()); } }
打印日志-加载的资源
banner printedbanner = printbanner(environment);
根据不同的webapplicationtype创建context
context = createapplicationcontext();
3.4 refreshcontext
支持定制刷新
/** * register a shutdown hook with the jvm runtime, closing this context * on jvm shutdown unless it has already been closed at that time. * <p>this method can be called multiple times. only one shutdown hook * (at max) will be registered for each context instance. * @see java.lang.runtime#addshutdownhook * @see #close() */ void registershutdownhook();
3.5 afterrefresh
刷新后的实现方法暂未实现
/** * called after the context has been refreshed. * @param context the application context * @param args the application arguments */ protected void afterrefresh(configurableapplicationcontext context, applicationarguments args) { }
3.6 listeners.started(context);
到此为止, spring application的环境和资源都加载完毕了;发布应用上下文启动完成事件;执行所有 runner 运行器 - 执行所有 applicationrunner 和 commandlinerunner 这两种运行器。
// 启动 callrunners(context, applicationarguments);
3.7 listeners.running(context);
触发所有 springapplicationrunlistener 监听器的 running 事件方法
(完)
本人免费整理了java高级资料,涵盖了java、redis、mongodb、mysql、zookeeper、spring cloud、dubbo高并发分布式等教程,一共30g,需要自己领取。
传送门:https://mp.weixin.qq.com/s/osb-bol6w-zltstttkqmpq