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