如果要二开SpringBoot,本质就是利用SpringBoot的生命周期事件,在不同的时间节点会收到对应的通知,然后干自己想干的事情,这就是二开。
那么SpringBoot是怎么设计自己的生命周期的
1 有哪些生命周期
spring体系的ApplicationEvent派生出spring boot体系的SpringApplicationEvent
在此基础上我按照从先到后的顺序,spring boot定义了生命周期
- 1 ApplicationStartingEvent
- 2 ApplicationEnvironmentPreparedEvent
- 3 ApplicationContextInitializedEvent
- 4 ApplicationPreparedEvent
- 5 ApplicationStartedEvent
- 6 ApplicationFailedEvent
- 7 ApplicationReadyEvent
这7大事件本质都是spring framework的事件体系,那么spring boot是怎么处理事件的呢
看过Spring-01-什么是context就应该清楚在执行完refresh后就拥有了发布事件能力
- 第1 spring boot在refresh之前是完全没有建立spring framework的事件发布能力的
- 第2 自始至终 这几个事件的发布spring boot都是用自己建设的机制完成的
2 EventPublishingRunListener
spring boot把这个类注册在了spring.factories里面在启动过程中会扫描加载出来
SpringBoot-03-SpringBoot的SPI
1 2
| SpringApplicationRunListeners listeners = getRunListeners(args);
|
1 2 3 4 5 6 7 8 9 10
|
EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; this.args = args; this.initialMulticaster = new SimpleApplicationEventMulticaster(); }
|
生命周期事件的发布就全靠它了,它用的实现就是Spring-11-事件传播器
3 模板+策略的设计
这些事件的发布流程都是一样的,此时就用到了模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction, @Nullable Consumer<StartupStep> stepAction) { StartupStep step = this.applicationStartup.start(stepName); this.listeners.forEach(listenerAction); if (stepAction != null) { stepAction.accept(step); } step.end(); }
|
那么只要在发布不同的事件时候丢一个不同的lambda过来就行,然后给转到事件发布器就行
1 2 3 4 5
| private void multicastInitialEvent(ApplicationEvent event) { refreshApplicationListeners(); this.initialMulticaster.multicastEvent(event); }
|
4 不同的事件
先看一下spring boot在整个启动过程中什么节点发送事件的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| public ConfigurableApplicationContext run(String... args) { Startup startup = Startup.create(); if (this.properties.isRegisterShutdownHook()) { SpringApplication.shutdownHook.enableShutdownHookAddition(); } DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); Banner printedBanner = printBanner(environment); context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); Duration timeTakenToStarted = startup.started(); if (this.properties.isLogStartupInfo()) { new StartupInfoLogger(this.mainApplicationClass, environment).logStarted(getApplicationLog(), startup); } listeners.started(context, timeTakenToStarted); callRunners(context, applicationArguments); } catch (Throwable ex) { throw handleRunFailure(context, ex, listeners); } try { if (context.isRunning()) { listeners.ready(context, startup.ready()); } } catch (Throwable ex) { throw handleRunFailure(context, ex, null); } return context; }
|
4.1 ApplicationStartingEvent
1 2 3 4 5 6 7 8 9
| void starting(ConfigurableBootstrapContext bootstrapContext, @Nullable Class<?> mainApplicationClass) { doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext), (step) -> { if (mainApplicationClass != null) { step.tag("mainApplicationClass", mainApplicationClass.getName()); } }); }
|
1 2 3 4
| @Override public void starting(ConfigurableBootstrapContext bootstrapContext) { multicastInitialEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args)); }
|
4.2 ApplicationEnvironmentPreparedEvent
1 2 3 4 5 6
| @Override public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) { multicastInitialEvent( new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment)); }
|
4.3 ApplicationContextInitializedEvent
1 2 3 4
| @Override public void contextPrepared(ConfigurableApplicationContext context) { multicastInitialEvent(new ApplicationContextInitializedEvent(this.application, this.args, context)); }
|
4.4 ApplicationPreparedEvent
1 2 3 4 5 6 7 8 9 10
| @Override public void contextLoaded(ConfigurableApplicationContext context) { for (ApplicationListener<?> listener : this.application.getListeners()) { if (listener instanceof ApplicationContextAware contextAware) { contextAware.setApplicationContext(context); } context.addApplicationListener(listener); } multicastInitialEvent(new ApplicationPreparedEvent(this.application, this.args, context)); }
|
4.5 ApplicationStartedEvent
1 2 3 4 5
| @Override public void started(ConfigurableApplicationContext context, @Nullable Duration timeTaken) { context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken)); AvailabilityChangeEvent.publish(context, LivenessState.CORRECT); }
|
4.6 ApplicationReadyEvent
1 2 3 4 5
| @Override public void ready(ConfigurableApplicationContext context, @Nullable Duration timeTaken) { context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken)); AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC); }
|