The listener
The listeners described above are listeners in SpringBoot. After creating the application context and before refreshing the container, Listeners are forwarded to the application context (see SpringApplication->prepareContext(): Listeners. ContextLoaded (context) for code for this step).
conclusion
- SpringApplication instantiates from
spring.factories
getorg.springframework.context.ApplicationListener
The fully qualified name of, instantiated, assigned tolisteners
Member variables - SpringApplication starts from
spring.factories
getorg.springframework.boot.SpringApplicationRunListener
Instantiation of the fully qualified name of theEventPublishingRunListener
Class to add listeners to its member variablesinitialMulticaster
Member variable ofdefaultRetriever
theapplicationListeners
In the ApplicationStartingEvent
Event, the listener starts- Once the environment is created,
ApplicationEnvironmentPreparedEvent
Event to load the configuration file - The IoC container is created,
ApplicationContextInitializedEvent
The event - Before the IoC container refreshes, the listener in SpringBoot is assigned to the application context, and then
ApplicationPreparedEvent
The event - IoC container singleton bean instantiation is complete. Starting later, the ApplicationListener implementation class in the Listeners = context listeners+ container.
ContextRefreshedEvent
Event to start a scheduled task - The Web server enables listening.
ServletWebServerInitializedEvent
The event - IoC process completed,
ApplicationStartedEvent
The event - Startup complete,
ApplicationReadyEvent
The event
If any of the above steps fail, the ApplicationFailedEvent event application context is closed, ContextClosedEvent event
As you can see, implementing the ApplicationListener interface and injecting the IoC container can only listen for events after the IoC instantiation singleton bean has completed. If you want to listen for events before, you can only listen in the way configured in Spring.Factories.
Closing the application context
The destruction of beans in the IoC phase has been described in the bean instantiation process. In addition, the destruction of beans can be triggered during the SpringBoot startup phase and the run phase.
Abnormal shutdown
SpringApplication->run(): try { ...... } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } SpringApplication->handleRunFailure(): try { handleExitCode(context, exception); if (listeners ! // ApplicationFailedEvent Events listeners. Failed (context, exception); } } finally { reportFailure(exceptionReporters, exception); // If the context is already created, call the close() method if (context! = null) { context.close(); } } AbstractApplicationContext->close(): doClose(); // --1 if (this.shutdownHook ! = null) { Runtime.getRuntime().removeShutdownHook(this.shutdownHook); / / - 2}Copy the code
This is what happens when the SpringBoot startup phase fails, with the context closed at point 1, where the bean is destroyed. Notice that there are “remove” in 2 places, indicating that they have “Add”.
SpringApplication->refreshContext(): // refresh context (context); if (this.registerShutdownHook) { context.registerShutdownHook(); } AbstractApplicationContext->registerShutdownHook(): if (this.shutdownHook == null) { this.shutdownHook = new Thread() { @Override public void run() { synchronized (startupShutdownMonitor) { doClose(); }}}; Runtime.getRuntime().addShutdownHook(this.shutdownHook); }Copy the code
ShutdownHook is a Thread class. Runtime.getruntime ().addShutdownHook(Thread hook) adds Thread classes and then calls Thread methods one by one before the JVM shuts down.
Run time shutdown
After the start, the execution System. The exit (0) closing process, eventually entering the AbstractApplicationContext – > doClose () method, notice the call stack, enforce the shutdownHook method of thread.
AbstractApplicationContext->doClose(): Active and closed are atomic Boolean classes, Ensure multi-threaded or repeated calls to shut down only once the if (this. Active. The get () && this.closed.com pareAndSet (false, True)) {// Publish ContextClosedEvent publishEvent(new ContextClosedEvent(this)); / / in the IoC container implementation Lifecycle interface beans, if set to return to the true, the implement method of stop this. LifecycleProcessor. OnClose (); // destroyBeans(); // Set the context state to close closeBeanFactory(); // Close and release the web server onClose(); this.active.set(false); }Copy the code
Addendum: Gracefully closing services in Docker
To kill a process, use the kill command, kill -9 to forcibly shut it down, kill -15 to prepare the process and then shut it down. For Java services, if it is forcibly shutdown, the thread method of shutdownHook will not be executed. If it is kill -15, it can be called gracefully shutdown.
Deploy SpringBoot to the server, usually into jar packages, build docker images and containers, and publish them in Docker. If you want to stop the service, use docker stop or docker restart command, however, only the process whose PID =1 can receive the interrupt signal, if the container process whose PID =1 is sh process, it does not have the ability to forward the end signal to its child process. So our real Java programs don’t get interrupt signals and can’t gracefully shut down.
The simplest solution is to configure the Java program as pid=1 process, in the Dockerfile java-jar to exec Java-jar.
Validation:
-
Docker execit /bin/bash docker execit /bin/bash docker execit /bin/bash
-
Execute docker stop to view the log. The @predestroy log is output and verified successfully.