The article directories

  • One, foreword
  • There are six methods for the SmartLifecycle interface
  • Start: The relationship between Spring container start and SmartLifecycle
    • 3.1 AbstractApplicationContext class refresh () method
    • The finishRefresh() method in 3.2 refresh()
    • The initLifecycleProcessor() method in 3.3 finishRefresh()
    • GetLifecycleProcessor of 3.4 finishRefresh () (). OnRefresh () method (DefaultLifecycleProcessor startBeans () – > start ())
    • 3.5 doStart DefaultLifecycleProcessor class () method
  • Close: The Spring container closes the relationship with SmartLifecycle
    • 4.1 doClose AbstractApplicationContext class () call DefaultLifecycleProcessor class onClose ()
    • 4.2 stop DefaultLifecycleProcessor class () call stopBeans () method
    • In 4.3 DefaultLifecycleProcessor stopBeans () call the stop () method
    • 4.4 The stop() method in the LifecycleGroup class calls the doStop() method
    • 4.5 DefaultLifecycleProcessor doStop in class () method
  • Lifecycle or SmartLifecycle, which will be used when customizing?
  • Six, thoroughly understand SmartLifeCycle 6 methods
    • 6.1 the start () method
      • The actual call location of the start() method
      • 6.1.2 How to write the logic of simulated start() method? Copy the original
    • 6.2 set the ()
      • The actual call location of the isRunning() method
      • 6.2.2 How to write the logic of isRunning() method? Copy the original
    • 6.3 isAutoStartup ()
      • 6.3.1 isAutoStartup() Actual call location
      • 6.3.2 What is the logic of the simulated isAutoStartup() method? Copy the original
    • 6.4 getPhase ()
      • 6.4.1 Actual call location of the getPhase() method
      • 6.4.2 getPhase() method simulation, imitate the original good
    • 6.5 Actual call location of stop() method and simulation of stop() method
      • 6.5.1 Where the stop() method is actually called
      • 6.5.2 How to write the logic of simulated stop() method? Copy the original
    • 6.6 stop (Runnable Runnable)
      • 6.6.1 Actual location where the stop(Runnable Runnable) method is called
      • 6.6.2 What is the logic of simulated stop(Runnable Runnable) method? Copy the original
    • 6.7 CountDownLatch
      • 6.7.1 CountDownLatch The main latch waits for sub-threads
      • 6.7.2 Set countDownBeanNames Function: Used to determine whether a timeout occurs
      • 6.7.3 Set lifecycleBeanNames Functions: Saves a Map

One, foreword

Summary of this paper: learning methods: based on six methods, one by one to see the simulation to practice, six methods of simulation, six methods of practice

Classes involved: AbstractApplicationContext, DefaultLifecycleProcessor, ApplicationListenerDetector, SmartLifecycle and CountDownLatch, the first three are very important, The last two are only slightly touched upon.

Goldfinger: We implement the SmartLifeCycle interface and annotate this class with @Component

This chapter consists of the following parts:

  1. SmartLifecycle 6 methods;
  2. Spring container startup in relation to SmartLifecycle;
  3. The Spring container closes the relationship with SmartLifecycle;
  4. Lifecycle and SmartLifecycle;

There are six methods for the SmartLifecycle interface

Take a look at the class diagram for the SmartLifecycle interface:

As shown in the figure above, After Lifecycle and Phased interfaces are inherited, SmartLifecycle defines a total of six methods. To facilitate the subsequent source code analysis, we will give a brief introduction:

methods role
start() After the bean is initialized, this method is executed (actual:, simulated: print is fine).
stop() If SmartLifecycle is implemented, stop(Runnable) is called; If Lifecycle is only implemented, stop() is called
isRunning() The current state
getPhase() The return value determines the order in which the start method is executed in many Lifecycle implementation classes (as is stop)
isAutoStartup() Check the return value of the start method before executing it. If false is returned, the start method will not be executed
stop(Runnable) If SmartLifecycle is implemented, stop(Runnable) is called; If Lifecycle is only implemented, stop() is called

The six methods of the full text of the main line: 1, to see how the six methods in the source code; 2. See how six methods implement SmartLifeCycle in a custom mock interface. How to simulate in simulation

As can be seen from the above listing, the ability to sense changes in the container will ultimately come from Lifecycle, and SmartLifecycle is just an enhanced version of Lifecycle. You can customize the priority (getPhase) and decide whether or not to start with the container (isAutoStartup). And the ability to accept a runnable object (stop(runnable)) when stopped;

Start: The relationship between Spring container start and SmartLifecycle

Now you can use the Spring source code to look at SmartLifecycle usage scenarios, starting with spring container initialization;

3.1 AbstractApplicationContext class refresh () method

Hands, refresh AbstractApplicationContext class method, in bean instantiation and after the initialization, can call finishRefresh method, shown in the diagram below the red box:

The finishRefresh() method in 3.2 refresh()

Following the above, the finishRefresh method contents are as follows, with the Chinese annotations providing a brief overview of each method:

protected void finishRefresh() {// LifecycleProcessor instance initialization, // LifecycleProcessor is a manager for all Lifecycle implementation classes that contain operations on Lifecycle.  Lifecycle implementation class start method getLifecycleProcessor().onrefresh (); ContextRefreshedEvent publishEvent(new ContextRefreshedEvent(this)); / / if the configuration MBeanServer, completed on the MBeanServer registration LiveBeansView. RegisterApplicationContext (this); }Copy the code

The initLifecycleProcessor() and getLifecycleProcessor().onRefresh() methods in the above code are relevant to the topic of this chapter. The other two methods are not covered in this chapter. Let’s start with initLifecycleProcessor;

Auric goldfinger:

How does Spring actually perform when implementing the SmartLifeCycle interface

The initLifecycleProcessor() method in 3.3 finishRefresh()

The initLifecycleProcessor method assigns a value to the applicationContext member variable lifecycleProcessor. If you already have a bean named “lifecycleProcessor”, LifecycleProcessor is equal to the bean, otherwise it instantiates a DefaultLifecycleProcessor object, let lifecycleProcessor is equal to this object, And register this object in the Spring environment (named “lifecycleProcessor”), source code is as follows:

protected void initLifecycleProcessor() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if(beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) { this.lifecycleProcessor = beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class); }}else{ DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor(); defaultProcessor.setBeanFactory(beanFactory); this.lifecycleProcessor = defaultProcessor; beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor); }}Copy the code

Goldfinger: initLifecycleProcessor()= Setup variable + register bean initLifecycleProcessor() each branch in initLifecycleProcessor() does two things: Setup variables lifecycleProcessor and objects to register to Spring (in fact, many places in Spring are initialized to do both things, set variables and register beans) (1) Spring IOC container already exists in the bean, directly set variables; (2) The bean does not exist in the Spring IOC container, set the variable and register the bean.

First, assign the defaultProcessor variable, and second, inject the defaultProcessor object into the Spring IOC container (BeanFactory and Application) : (1) If the Spring IOC container already has a bean named “lifecycleProcessor”, the lifecycleProcessor is equal to this bean. (2) If the Spring IOC container has a bean named “lifecycleProcessor”, the lifecycleProcessor is equal to this bean. Not instantiate a DefaultLifecycleProcessor object, let lifecycleProcessor is equal to this object, and the object to be registered to spring environment (called “lifecycleProcessor”)

Here, the LIFECYCLE_PROCESSOR_BEAN_NAME constant is the string “lifecycleProcessor”.



If the business is not a custom LifecycleProcessor, you create a DefaultLifecycleProcessor object by default

When you return, you return directly

3.4 finishRefresh getLifecycleProcessor in () (). OnRefresh () method (DefaultLifecycleProcessor startBeans () – > start ())

To answer the above, is now a getLifecycleProcessor (.) onRefresh () implementation, if the business is not a custom LifecycleProcessor, will create a DefaultLifecycleProcessor object by default, So is DefaultLifecycleProcessor onRefresh method of execution, to see the source code:

@Override
public void onRefresh() {
    startBeans(true);
    this.running = true;
}
Copy the code

Auric goldfinger: Overridden methods can also be called, Such as common override the toString () is used here getLifecycleProcessor () onRefresh () call DefaultLifecycleProcessor onRefresh method AbstractApplicationContext constructor is mobilized their classes to rewrite the refresh () method

Expand the startBeans method and note that the parameter autoStartupOnly equals true:

The input parameter is true and the condition is if (! autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) The bean must implement the SmartLifecycle interface and isAutoStartup() returns true

DefaultLifecycleProcessor class private void startBeans (Boolean autoStartupOnly) {/ / all the instance Lifecycle interface, the key of this map is the name of the instance, Lifecycle> lifecycleBeans = getLifecycleBeans(); <Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>(); // Use map directly without worrying about thread safetyfor(Map.Entry<String, ? Extends Lifecycle> entry: lifecycleBeans.entryset ()) {Lifecycle bean = entry.getValue(); // The map element is entry, where the value is the specific instance of the bean //autoStartupOnly equalstrue, the bean must implement the SmartLifecycle interface and isAutoStartup() returnstrue, will be put into the LifecycleGroup (later removed from the LifecycleGroup to execute start())if(! autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) { int phase = getPhase(bean); LifecycleGroup group = phases.get(phase);if(group == null) { group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly); Lifecycle instance Phases. Put (phase, group); // Lifecycle instance Phases. } // Add (entry.getkey (), bean); // Add (entry.getkey (), bean); }}if(phases.size() > 0) { List<Integer> keys = new ArrayList<Integer>(phases.keySet()); // Sort by all phase values, then execute the bean start method one by one, each time with a batch of the same collections.sort (keys) phases;for(Integer key: keys) {Lifecycle instances will be called phases.get(key).start(); } } } public voidstart() {
		if (this.members.isEmpty()) {
			return;
		}
		Collections.sort(this.members);
		for(LifecycleGroupMember member : this.members) { doStart(this.lifecycleBeans, member.name, this.autoStartupOnly); }}Copy the code

In the source code, ConcurrentHashMap is used to ensure thread-safety, and HashMap is not used to ensure thread-safety





The map element is Entry, including four attributes such as key value. The startBeans() method uses getLifeCycles(), which returns the LinkedHashMap and ensures insertion order.

3.5 doStart DefaultLifecycleProcessor class () method

The place where start for an instance of SmartLifecycle is called is inside the LifecycleGroup, and the corresponding method is doStart, as shown below, which takes precedence over dependent beans:

Priority depends on the bean is to point to: a String [] dependenciesForBean = enclosing the beanFactory. GetDependenciesForBean (beanName); for (String dependency : DependenciesForBean (doStart(lifecycleBeans, dependency, autoStartupOnly)) {$dependenciesForBean (lifecycleBeans, dependency, autoStartupOnly); }

private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
        Lifecycle bean = lifecycleBeans.remove(beanName);
        if(bean ! = null && ! this.equals(bean)) { String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);for(String dependency : DependenciesForBean (doStart(lifecycleBeans, dependency, autoStartupOnly)) {$dependenciesForBean (lifecycleBeans, dependency, autoStartupOnly); } // return isRunningfalseSecond: cannot be an implementation class for SmartLifecycle. ** If SmartLifecycle is an implementation class, its isAutoStartup method must returntrue支那if(! bean.isRunning() && (! autoStartupOnly || ! (bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {if (logger.isDebugEnabled()) {
                    logger.debug("Starting bean '" + beanName + "' of type [" + bean.getClass() + "]"); } try { bean.start(); } catch (Throwable ex) { throw new ApplicationContextException; }}}}Copy the code

Summary: Spring container initialization for SmartLifecycle instance processing logic:

  1. Lifecycle processing is delegated to LifecycleProcessor, so have this instance ready; (The first and second steps are the entry, and the third step is to prepare the instance, set the properties and inject the bean.)
  2. Group all Lifecycle instances by phase; (Get the instance and group it, before and in the middle of Step 4 above)
  3. Execute the start method of each Lifecycle object in turn, starting with the group with the smallest phase value; (After Step 4 above and Step 5 above)

Startup process:

AbstractApplicationContext class refresh () method — > refresh () in the finishRefresh () method — > finishRefresh getLifecycleProcessor in () ().onRefresh()–> startBeans() –> start() –> doStart() the entire process, which contains doStart() ‘s own recursive call

Closing process:

AbstractApplicationContext class doClose () – > DefaultLifecycleProcessor in the classonClose()— > DefaultLifecycleProcessor stopBeans in class () – > LifecycleGroup class the stop () – > DefaultLifecycleProcessor doStop in class () (including, DoStop () contains recursive calls.

Just notice a recursive call here to do the iterative work



Close: The Spring container closes the relationship with SmartLifecycle

To analyze how SmartLifecycle will sense the closure of the Spring container, start by understanding the call stack for the Stop method, starting with the LifecycleProcessor interface:

public interface LifecycleProcessor extends Lifecycle { void onRefresh(); // Lifecycle processing is delegated to LifecycleProcessor, onRefresh() is aware of starting void onClose(); // Lifecycle processing is delegated to LifecycleProcessor, onClose() is perceptual closing}Copy the code

As shown above, the only way to sense container closure is to call onClose.

Summary: LifeCycle is inherited by the LifecycleProcessor interface, with only two new methods, onRefresh() aware that LifeCycle is started and onClose() aware that LifeCycle is closed.

4.1 doClose AbstractApplicationContext class () call DefaultLifecycleProcessor class onClose ()

Start from AbstractApplicationContext doClose () method: LifecycleProcessor onClose method is invoked in AbstractApplicationContext doClose method, shown in the diagram below the red box,(Goldfinger: doClose() brings together the basic logic to perform when a container is closed, many of which are here.)

Hammered out call logic, can visit the DefaultLifecycleProcessor SmartLifecycle instance how stop method is invoked;

Startup process:

AbstractApplicationContext class refresh () method — > refresh () in the finishRefresh () method — > finishRefresh getLifecycleProcessor in () ().onRefresh()–> startBeans() –> start() –> doStart() the entire process, which contains doStart() ‘s own recursive call

Closing process:

AbstractApplicationContext class doClose () – > DefaultLifecycleProcessor in the classonClose()— > DefaultLifecycleProcessor stopBeans in class () – > LifecycleGroup class the stop () – > DefaultLifecycleProcessor doStop in class () (including, DoStop () contains recursive calls.



CTRL + Alt +B to go to onClose()

4.2 stop DefaultLifecycleProcessor class () call stopBeans () method

Stop method of DefaultLifecycleProcessor call stopBeans method first, then the member variable running set to false, said in the operation of the state is not:

@Override
public void stop() {
    stopBeans();
    this.running = false;
}
Copy the code

In 4.3 DefaultLifecycleProcessor stopBeans () call the stop () method

Expand the stopBeans method: Similar to startBeans

The stopBeans() method is similar to the startBeans() method

private void stopBeansLifecycle <String, Lifecycle> lifecycleBeans = getLifecycleBeans(); Lifecycle <String, Lifecycle> lifecycleBeans (); Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();for(Map.Entry<String, Lifecycle> entry : lifecycleBeans.entrySet()) { Lifecycle bean = entry.getValue(); Int shutdownOrder = getPhase(bean); //SmartLifecycle instance will return via getPhase. LifecycleGroup group = phases.get(shutdownOrder);if (group == null) {
                group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans, false); Lifecycle instance phases. Put (shutdownOrder, group); // Lifecycle instance Phases. } group.add(entry.getKey(), bean); }if(phases.size() > 0) { List<Integer> keys = new ArrayList<Integer>(phases.keySet()); Collections.sort(keys, collections.reverseOrder ()); // Collections.sort(keys, collections.reverseOrder ());for(Integer key: keys) {// For Lifecycle instances of the same phase, execute the stop method phase.get (key).stop(); }}}Copy the code

Goldfinger: This code is similar to the start logic, except that it is executed in the opposite order. This is why getLifecycleBeans() uses LinkedHashMap, which is called by startBeans() and stopBeans() at the same time

4.4 The stop() method in the LifecycleGroup class calls the doStop() method

Look inside LifecycleGroup’s stop method and see how Lifecycle instance doStop is called:

public void stop() {
            if (this.members.isEmpty()) {
                return;
            }
            if (logger.isInfoEnabled()) {
                logger.info("Stopping beans in phase "+ this.phase); } Collections.sort(this.members, Collections.reverseOrder()); // There is synchronization logic that CounDownLatch counts the number of Lifecycle instances in the current LifecycleGroup. Constantly reduce CountDownLatch when closed. Latch = new CountDownLatch(this.smartMemberCount); Set<String> countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet<String>());for(LifecycleGroupMember member : This.members) {// This is important because in the doStop method, SmartLifecycle's stop method will be executed in a new thread. If a dependent bean is found, the stop method will be executed first. Lifecycle instance (Lifecycle) is A dependent bean on instance A (Lifecycle instance A). Stop (Lifecycle instance A) will remove Lifecycle from this.lifecycleBeans. So this. LifecycleBeans no longer existsif (this.lifecycleBeans.containsKey(member.name)) {
                    doStop(this.lifecycleBeans, member.name, latch, countDownBeanNames);
                }
                else if(member.bean instanceof SmartLifecycle) { latch.countDown(); }} try {Lifecycle will wait until all Lifecycle instances are executed and the current thread latches. Await (this.timeout, timeunit.milliseconds);if(latch.getCount() > 0 && ! countDownBeanNames.isEmpty() && logger.isWarnEnabled()) { logger.warn("Failed to shut down " + countDownBeanNames.size() + " bean" +
                            (countDownBeanNames.size() > 1 ? "s" : "") + " with phase value " +
                            this.phase + " within timeout of " + this.timeout + ":"+ countDownBeanNames); } } catch (InterruptedException ex) { Thread.currentThread().interrupt(); }}Copy the code

There is one caveat to the above code:

SmartLifecycle instances have a stop(Runnable) method that can execute the stop logic in another thread. In this way, multiple Instances of SmartLifecycle can execute the stop logic in parallel, which can improve the execution speed. The current thread uses CountDownLatch to wait for all stop threads, and a timeout is set to avoid an indefinite wait.

4.5 DefaultLifecycleProcessor doStop in class () method

Finally take a look at the LifecycleGroup stop method which is called looping through Lifecycle’s stop method, which will actually call into Lifecycle’s stop method, as well as the multi-threaded logic we analyzed above:

private void doStop(Map<String, ? extends Lifecycle> lifecycleBeans, final String beanName, final CountDownLatch latch, Final Set<String> countDownBeanNames) {// Remove current bean from member variable lifecycleBeans, Lifecycle bean = lifecycleBeans.remove(beanName); Lifecycle bean = lifecycleBeans.remove(beanName);if(bean ! = null) {/ / find rely on beans, to ensure implementation depend on the bean to stop calling through the iteration method String [] dependentBeans = enclosing the beanFactory. GetDependentBeans (beanName);for(String dependentBean: dependentBeans) {// Iterate doStop(lifecycleBeans, dependentBean, latch, countDownBeanNames); } try {//isRunning returnstrueLifecycle will be executed so be careful when customizing Lifecycleif (bean.isRunning()) {
                    if (bean instanceof SmartLifecycle) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Asking bean '" + beanName + "' of type [" + bean.getClass() + "] to stop"); } countDownBeanNames.add(beanName); // Pass in the CountDownLatch (+ 1) logic so that a new thread can execute the logic in SmartLifecycle's stop method. Do not execute the logic in Runnable until the end of the process so that the main thread does not wait. ((SmartLifecycle) bean).stop(newRunnable() {
                            @Override
                            public void run() {
                                latch.countDown();
                                countDownBeanNames.remove(beanName);
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Bean '" + beanName + "' completed its stop procedure"); }}}); }else {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Stopping bean '" + beanName + "' of type [" + bean.getClass() + "]"); } // If it is not a SmartLifecycle instance, stop is called and bean.stop() is executed in the current thread;if (logger.isDebugEnabled()) {
                            logger.debug("Successfully stopped bean '" + beanName + "'"); }}}else if(bean instanceof SmartLifecycle) {// The number of counters in CountDownLatch is calculated by the number of Instances of SmartLifecycle. If the count is not in the runing state, the stop method of the instance will not be called. Instead of waiting for the stop, the latch is reduced by one latch.countdown (); } } catch (Throwable ex) {if (logger.isWarnEnabled()) {
                    logger.warn("Failed to stop bean '" + beanName + "'", ex); }}}}Copy the code

LifecycleGroup has passed the Runnable to the implementation class when stop(Runnable) is called. Therefore, the implementation class should remember to execute the Runnable run method, otherwise it will cause the external call logic parameters are not prepared, affecting the execution of the calling thread;

This is the closing container phase of the SmartLifecycle instance processing logic, briefly summarized as follows:

  1. AbstractApplicationContext doClose methods in closed containers when implemented, this call LifecycleProcessor onClose method, LifecycleProcessor is responsible for all instances of Lifecycle of closing operation; (Steps 1 and 2)
  2. Group all Lifecycle instances by phase; (Between steps 3 and 4)
  3. Execute the stop method on each Lifecycle object, starting with the group with the largest phase value; (After Step 4)
  4. For each SmartLifecycle instance, if you want to execute in parallel to speed up the stop execution, you can use a new thread in the stop method to execute the stop business logic, but don’t forget to call the Runnable parameter run method to complete the main thread count and statistics. (Step 6 inside the doStop() method)
  5. The main thread uses CountDownLatch and after calling the Stop method of the SmartLifecycle instance will wait until the count reaches the total number of SmartLifecycle instances or wait for a timeout, and then continue to execute backward. Latch.await (this.timeout, timeunit.milliseconds); Lifecycle will wait until all Lifecycle instances have executed.

Lifecycle is done when the container is started. Lifecycle is done when the container is closed.

Goldfinger: Close logic: from stopBeans()->stop()->doStop()

The above code is similar to the start logic, except that the order of execution is reversed. Enter stop() to check the stop logic:



Enter the doStop() method

Lifecycle or SmartLifecycle, which will be used when customizing?

There are two cases:

  1. If there is no order required for execution and no performance or time required at shutdown, Lifecycle will be used as it is simpler;
  2. If you care about order and expect multiple Lifecycle instances to execute in parallel and end quickly when closed, SmartLifecycle is definitely more suitable.

Six, thoroughly understand SmartLifeCycle 6 methods

Goldfinger: six methods, the full text of the core, the actual source code for six methods of processing, simulation of six methods of logic

For the 6 methods, just know where the actual call is and how the logic is written

6.1 the start () method

The actual call location of the start() method

The start() method is called in the source code as follows:

// LifecycleProcessor is the manager for all Lifecycle implementation classes and contains operations that will Lifecycle. Lifecycle implementation class start method getLifecycleProcessor().onrefresh ();Copy the code

These two lines of code initialize the LifecycleProcessor, then use it to call the start method of the Lifecycle implementation class, and finally use it to call the Stop method of the Lifecycle implementation class.

StartBeans – > start () – > doStart ()

6.1.2 How to write the logic of simulated start() method? Copy the original

Emulated start() method, set certain flag bit, print a sentence

@Override
public void start() {
    Utils.printTrack("do start"); / / set tofalseSetRunningFlag (true);
}
Copy the code

Goldfinger: Simulate why you set your own runningFlag variable in code:

We don’t use our custom runningFlag for any branch logic, so this variable runningFlag doesn’t have any effect, but it’s the isRunning variable in the code that is valuable

Goldfinger: The ostensible reason for implementing SmartLifeCycle methods in mock classes and @Component annotations: Instance of Xxx



Practical reasons:

6.2 set the ()

The actual call location of the isRunning() method

When is the actual isRuninng() called, that’s what matters, the logic just returns a variable, easy enough

There are only two actual call locations, a judgment in doStart() and a judgment in doStop()



6.2.2 How to write the logic of isRunning() method? Copy the original

The logic of the simulated isRunning() is the same as that of the actual isRunning()

@Override
    public boolean isRunning() {
        return isRunningFlag();
    }
Copy the code

Goldfinger: logic in doStop()





6.3 isAutoStartup ()

6.3.1 isAutoStartup() Actual call location

Two use locations are startBeans() and doStart()



6.3.2 What is the logic of the simulated isAutoStartup() method? Copy the original

@Override
    public boolean isAutoStartup() {// Only set totrueThe start method is called backreturn true;
    }
Copy the code

6.4 getPhase ()

6.4.1 Actual call location of the getPhase() method



The getPhase() method is useful to us only for calls in startBeans() and stopBeans()

6.4.2 getPhase() method simulation, imitate the original good



Because SmartLifeCycle is a Phased,



So, execute ((Phased) bean).getPhase()









This is how SmartLifeCycle implements the Phased interface to sort start()



   @Override
    public int getPhase() {
        return 666;
    }
Copy the code

6.5 Actual call location of stop() method and simulation of stop() method

6.5.1 Where the stop() method is actually called

Where the stop() method is actually called: closes the custom relationship in the logic, and also calls the custom start() method when started

6.5.2 How to write the logic of simulated stop() method? Copy the original

Emulation of the stop() method: Just set the flag bit and print a sentence

  @Override
    public void stop() {
        Utils.printTrack("do stop"); / / set tofalseSetRunningFlag (false);
    }
Copy the code

6.6 stop (Runnable Runnable)

6.6.1 Actual location where the stop(Runnable Runnable) method is called

Call it here, if we rewrite,

((SmartLifecycle) bean).stop(() -> {
Copy the code



Expand -> is new Runnable() good called here

  if (bean.isRunning()) {
                    if (bean instanceof SmartLifecycle) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Asking bean '" + beanName + "' of type [" + bean.getClass() + "] to stop"); } countDownBeanNames.add(beanName); // Pass in the CountDownLatch (+ 1) logic so that a new thread can execute the logic in SmartLifecycle's stop method. Do not execute the logic in Runnable until the end of the process so that the main thread does not wait. ((SmartLifecycle) bean).stop(newRunnable() {
                            @Override
                            public void run() {
                                latch.countDown();
                                countDownBeanNames.remove(beanName);
                                if (logger.isDebugEnabled()) {
                                    logger.debug("Bean '" + beanName + "' completed its stop procedure"); }}}); }Copy the code

6.6.2 What is the logic of simulated stop(Runnable Runnable) method? Copy the original

Copy SmartLifeCycle’s stop(Runnable Runnable) method (this.stop(); The callback. The run ())

Print a line, set the flag bit, and callback.run();

  @Override
    public void stop(Runnable callback) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                Utils.printTrack("do stop with callback param"); / / set tofalseSetRunningFlag (false); Callback has CountDownLatch instances. The total number of SmartLifecycle objects is the number of CountDownLatch instances. CountDownLatch instances are reduced by one only when this method is called backwait; callback.run(); } }).start(); }Copy the code

6.7 CountDownLatch

6.7.1 CountDownLatch The main latch waits for sub-threads

CountDownLatch Limitations of the latch: Just counting in concurrent cases, just changing a number, just serving SmartLifeCycle and its subclasses, just latching. Await (this.timeout, timeunit.milliseconds) in stop() methods; The trigger condition is only that the child thread executes after the main thread executes

The count in CountDownLatch is the number of Lifecycle instances in the current LifecycleGroup that will be reduced as Lifecycle instances are closed, either the stop method or the doStop method is reduced to 0 and the main thread is ready to execute

The CountDownLatch class, introduced in JDk1.5, is in the java.util.concurrent package, so it has to do with concurrency.

Goldfinger: Latch is determined using the smartMemberCount variable and is determined using the stop() and doStop() methods

First, latch is determined using the smartMemberCount variable:

The smartMemberCount variable is only identified in the Add method of the LifecycleGroup class (SmartLifeCycle and its subclass instances must be ++), Only used in the LifecycleGroup class’s stop method to initialize the latch capacity



Second, latch is established using the stop() and doStop() methods:

Either stop() or doStop() must be an instance of SmartLifeCycle and its subclasses latch.countdown ();

Stop () method:

Stop () CountDownLatch = new CountDownLatch(this.smartMemberCount); The constructor initializes the number of threads



DoStop () method:

Summary:

Latch is used only for SmartLifeCycle: Whether the LifecycleGroup’s add() method determines the smartMemberCount and then uses smartMemberCount to determine the number of latches, or latch.countdown (), the latch is used only for SmartLifeCycle.

6.7.2 Set countDownBeanNames Function: Used to determine whether a timeout occurs

CountDownBeanNames is determined in the stop() method and used in the stop() and doStop() methods

Stop() and doStop() doStop() processes beans contained within lifecycleBeanNames that fall into two categories that implement either the LifeCycle interface or the SmartLifeCycle interface and others, Not included in lifecycleBeanNames, but SmartLifeCycle implementation classes, are the ones that have been removed, Else if (member.bean instanceof SmartLifecycle) {// Already removed: must have been a dependent bean from another phase latch.countDown(); }

From the Latch variable of the CountDownLatch class to the countDownBeanNames variable of the Set:

Set<String> countDownBeanNames = Collections.synchronizedSet(new LinkedHashSet<String>());

The insertion order is guaranteed, but the stop() method does not add elements to the set



Look at the doStop() method,



6.7.3 Set lifecycleBeanNames Function: Store Map<beanName,bean>, recursive use



Ok, lifecycleBeans identified, see how and where it is used, in the doStart() and doStop() methods



Look at the doStart() method first



LifecycleBeans in the doStart() method are just passed parameters, not global lifecycleBeans,

Lifecyclebeans.remove (beanName) inside doStart(); If the key exists, the method returns the value previously mapped to the specified key, otherwise it returns NULL.

Just executing your own method completion does not have any effect on the global lifecycleBeans

Look again at the doStop() method

Interview Goldfinger

7.1 SmartLifecycle six methods

As shown in the figure above, After Lifecycle and Phased interfaces are inherited, SmartLifecycle defines a total of six methods. To facilitate the subsequent source code analysis, we will give a brief introduction:

methods role
start() After the bean is initialized, this method is executed (actual:, simulated: print is fine).
stop() If SmartLifecycle is implemented, stop(Runnable) is called; If Lifecycle is only implemented, stop() is called
isRunning() The current state
getPhase() The return value determines the order in which the start method is executed in many Lifecycle implementation classes (as is stop)
isAutoStartup() Check the return value of the start method before executing it. If false is returned, the start method will not be executed
stop(Runnable) If SmartLifecycle is implemented, stop(Runnable) is called; If Lifecycle is only implemented, stop() is called

The six methods of the full text of the main line: 1, to see how the six methods in the source code; 2. See how six methods implement SmartLifeCycle in a custom mock interface. How to simulate in simulation

As can be seen from the above listing, the ability to sense changes in the container will ultimately come from Lifecycle, and SmartLifecycle is just an enhanced version of Lifecycle. You can customize the priority (getPhase) and decide whether or not to start with the container (isAutoStartup). And the ability to accept a runnable object (stop(runnable)) when stopped;

7.2 Relationship between Spring Container Startup and SmartLifecycle

Startup process: AbstractApplicationContext class refresh () method — > refresh finishRefresh in () () method — — > GetLifecycleProcessor ().onRefresh() –> startBeans() –> start() –> doStart() Recursive call closure process containing doStart() itself: AbstractApplicationContext class doClose () – > DefaultLifecycleProcessor onClose in class () – > DefaultLifecycleProcessor in the class StopBeans () – > LifecycleGroup class the stop () – > DefaultLifecycleProcessor doStop in class () (including, doStop () contains the recursive call)

Summary: Spring container initialization for SmartLifecycle instance processing logic:

  1. Lifecycle processing is delegated to LifecycleProcessor, so have this instance ready; (The first and second steps are the entry, and the third step is to prepare the instance, set the properties and inject the bean.)
  2. Group all Lifecycle instances by phase; (Get the instance and group it, before and in the middle of Step 4 above)
  3. Execute the start method of each Lifecycle object in turn, starting with the group with the smallest phase value; (After Step 4 above and Step 5 above)

7.3 Closing the Relationship between the Spring Container and SmartLifecycle

This is the closing container phase of the SmartLifecycle instance processing logic, briefly summarized as follows:

  1. AbstractApplicationContext doClose methods in closed containers when implemented, this call LifecycleProcessor onClose method, LifecycleProcessor is responsible for all instances of Lifecycle of closing operation; (Steps 1 and 2)
  2. Group all Lifecycle instances by phase; (Between steps 3 and 4)
  3. Execute the stop method on each Lifecycle object, starting with the group with the largest phase value; (After Step 4)
  4. For each SmartLifecycle instance, if you want to execute in parallel to speed up the stop execution, you can use a new thread in the stop method to execute the stop business logic, but don’t forget to call the Runnable parameter run method to complete the main thread count and statistics. (Step 6 inside the doStop() method)
  5. The main thread uses CountDownLatch and after calling the Stop method of the SmartLifecycle instance will wait until the count reaches the total number of SmartLifecycle instances or wait for a timeout, and then continue to execute backward. Latch.await (this.timeout, timeunit.milliseconds); Lifecycle will wait until all Lifecycle instances have executed.

7.4 Lifecycle and SmartLifecycle Selection Questions

There are two cases:

  1. If there is no order required for execution and no performance or time required at shutdown, Lifecycle will be used as it is simpler;
  2. If you care about order and expect multiple Lifecycle instances to execute in parallel and end quickly when closed, SmartLifecycle is definitely more suitable.

Eight, summary

SmartLifeCycle completed

Play code every day, progress every day!!