1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.util.Lifecycle; 13 14 import core.atomic; 15 16 import hunt.util.Common; 17 import hunt.logging.ConsoleLogger; 18 19 /** 20 * A common interface defining methods for start/stop lifecycle control. 21 * The typical use case for this is to control asynchronous processing. 22 * <b>NOTE: This interface does not imply specific auto-startup semantics. 23 * Consider implementing {@link SmartLifecycle} for that purpose.</b> 24 * 25 * <p>Can be implemented by both components (typically a Spring bean defined in a 26 * Spring context) and containers (typically a Spring {@link ApplicationContext} 27 * itself). Containers will propagate start/stop signals to all components that 28 * apply within each container, e.g. for a stop/restart scenario at runtime. 29 * 30 * <p>Can be used for direct invocations or for management operations via JMX. 31 * In the latter case, the {@link org.springframework.jmx.export.MBeanExporter} 32 * will typically be defined with an 33 * {@link org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler}, 34 * restricting the visibility of activity-controlled components to the Lifecycle 35 * interface. 36 * 37 * <p>Note that the present {@code Lifecycle} interface is only supported on 38 * <b>top-level singleton beans</b>. On any other component, the {@code Lifecycle} 39 * interface will remain undetected and hence ignored. Also, note that the extended 40 * {@link SmartLifecycle} interface provides sophisticated integration with the 41 * application context's startup and shutdown phases. 42 * 43 * @see SmartLifecycle 44 */ 45 interface Lifecycle { 46 /** 47 * Start this component. 48 * <p>Should not throw an exception if the component is already running. 49 * <p>In the case of a container, this will propagate the start signal to all 50 * components that apply. 51 */ 52 void start(); 53 54 /** 55 * Stop this component, typically in a synchronous fashion, such that the component is 56 * fully stopped upon return of this method. Consider implementing {@link SmartLifecycle} 57 * and its {@code stop(Runnable)} variant when asynchronous stop behavior is necessary. 58 * <p>Note that this stop notification is not guaranteed to come before destruction: 59 * On regular shutdown, {@code Lifecycle} beans will first receive a stop notification 60 * before the general destruction callbacks are being propagated; however, on hot 61 * refresh during a context's lifetime or on aborted refresh attempts, a given bean's 62 * destroy method will be called without any consideration of stop signals upfront. 63 * <p>Should not throw an exception if the component is not running (not started yet). 64 * <p>In the case of a container, this will propagate the stop signal to all components 65 * that apply. 66 * @see SmartLifecycle#stop(Runnable) 67 */ 68 void stop(); 69 70 71 /** 72 * Check whether this component is currently running. 73 * <p>In the case of a container, this will return {@code true} only if <i>all</i> 74 * components that apply are currently running. 75 * @return whether the component is currently running 76 */ 77 bool isRunning(); 78 } 79 80 81 /** 82 * Interface for objects that may participate in a phased 83 * process such as lifecycle management. 84 * 85 * @see SmartLifecycle 86 */ 87 interface Phased { 88 89 /** 90 * Return the phase value of this object. 91 */ 92 int getPhase(); 93 } 94 95 96 /** 97 * An extension of the {@link Lifecycle} interface for those objects that require to 98 * be started upon ApplicationContext refresh and/or shutdown in a particular order. 99 * The {@link #isAutoStartup()} return value indicates whether this object should 100 * be started at the time of a context refresh. The callback-accepting 101 * {@link #stop(Runnable)} method is useful for objects that have an asynchronous 102 * shutdown process. Any implementation of this interface <i>must</i> invoke the 103 * callback's {@code run()} method upon shutdown completion to avoid unnecessary 104 * delays in the overall ApplicationContext shutdown. 105 * 106 * <p>This interface extends {@link Phased}, and the {@link #getPhase()} method's 107 * return value indicates the phase within which this Lifecycle component should 108 * be started and stopped. The startup process begins with the <i>lowest</i> phase 109 * value and ends with the <i>highest</i> phase value ({@code Integer.MIN_VALUE} 110 * is the lowest possible, and {@code Integer.MAX_VALUE} is the highest possible). 111 * The shutdown process will apply the reverse order. Any components with the 112 * same value will be arbitrarily ordered within the same phase. 113 * 114 * <p>Example: if component B depends on component A having already started, 115 * then component A should have a lower phase value than component B. During 116 * the shutdown process, component B would be stopped before component A. 117 * 118 * <p>Any explicit "depends-on" relationship will take precedence over the phase 119 * order such that the dependent bean always starts after its dependency and 120 * always stops before its dependency. 121 * 122 * <p>Any {@code Lifecycle} components within the context that do not also 123 * implement {@code SmartLifecycle} will be treated as if they have a phase 124 * value of 0. That way a {@code SmartLifecycle} implementation may start 125 * before those {@code Lifecycle} components if it has a negative phase value, 126 * or it may start after those components if it has a positive phase value. 127 * 128 * <p>Note that, due to the auto-startup support in {@code SmartLifecycle}, a 129 * {@code SmartLifecycle} bean instance will usually get initialized on startup 130 * of the application context in any case. As a consequence, the bean definition 131 * lazy-init flag has very limited actual effect on {@code SmartLifecycle} beans. 132 * 133 * @author Mark Fisher 134 */ 135 interface SmartLifecycle : Lifecycle, Phased { 136 137 /** 138 * Returns {@code true} if this {@code Lifecycle} component should get 139 * started automatically by the container at the time that the containing 140 * {@link ApplicationContext} gets refreshed. 141 * <p>A value of {@code false} indicates that the component is intended to 142 * be started through an explicit {@link #start()} call instead, analogous 143 * to a plain {@link Lifecycle} implementation. 144 * @see #start() 145 * @see #getPhase() 146 */ 147 bool isAutoStartup(); 148 149 /** 150 * Indicates that a Lifecycle component must stop if it is currently running. 151 * <p>The provided callback is used by the {@link LifecycleProcessor} to support 152 * an ordered, and potentially concurrent, shutdown of all components having a 153 * common shutdown order value. The callback <b>must</b> be executed after 154 * the {@code SmartLifecycle} component does indeed stop. 155 * <p>The {@link LifecycleProcessor} will call <i>only</i> this variant of the 156 * {@code stop} method; i.e. {@link Lifecycle#stop()} will not be called for 157 * {@code SmartLifecycle} implementations unless explicitly delegated to within 158 * the implementation of this method. 159 * @see #stop() 160 * @see #getPhase() 161 */ 162 void stop(Runnable callback); 163 164 alias stop = Lifecycle.stop; 165 166 int getPhase(); 167 168 } 169 170 /** 171 */ 172 abstract class AbstractLifecycle : Lifecycle { 173 174 protected shared bool _isRunning; 175 176 this() { 177 178 } 179 180 bool isRunning() { 181 return _isRunning; 182 } 183 184 bool isStopped() { 185 return !_isRunning; 186 } 187 188 void start() { 189 if (cas(&_isRunning, false, true)) { 190 initialize(); 191 } else { 192 version(HUNT_DEBUG) warning("Starting repeatedly!"); 193 } 194 } 195 196 void stop() { 197 if (cas(&_isRunning, true, false)) { 198 destroy(); 199 } else { 200 version(HUNT_DEBUG) warning("Stopping repeatedly!"); 201 } 202 } 203 204 abstract protected void initialize(); 205 206 abstract protected void destroy(); 207 }