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

  1. SpringApplication instantiates fromspring.factoriesgetorg.springframework.context.ApplicationListenerThe fully qualified name of, instantiated, assigned tolistenersMember variables
  2. SpringApplication starts fromspring.factoriesgetorg.springframework.boot.SpringApplicationRunListenerInstantiation of the fully qualified name of theEventPublishingRunListenerClass to add listeners to its member variablesinitialMulticasterMember variable ofdefaultRetrievertheapplicationListenersIn the
  3. ApplicationStartingEventEvent, the listener starts
  4. Once the environment is created,ApplicationEnvironmentPreparedEventEvent to load the configuration file
  5. The IoC container is created,ApplicationContextInitializedEventThe event
  6. Before the IoC container refreshes, the listener in SpringBoot is assigned to the application context, and thenApplicationPreparedEventThe event
  7. IoC container singleton bean instantiation is complete. Starting later, the ApplicationListener implementation class in the Listeners = context listeners+ container.ContextRefreshedEventEvent to start a scheduled task
  8. The Web server enables listening.ServletWebServerInitializedEventThe event
  9. IoC process completed,ApplicationStartedEventThe event
  10. Startup complete,ApplicationReadyEventThe 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:

  1. Docker execit /bin/bash docker execit /bin/bash docker execit /bin/bash

  2. Execute docker stop to view the log. The @predestroy log is output and verified successfully.