2020import java .util .Collections ;
2121import java .util .HashMap ;
2222import java .util .LinkedHashMap ;
23- import java .util .LinkedHashSet ;
2423import java .util .List ;
2524import java .util .Map ;
2625import java .util .concurrent .CountDownLatch ;
@@ -47,20 +46,20 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
4746
4847 private final Log logger = LogFactory .getLog (this .getClass ());
4948
50- private volatile long shutdownGroupTimeout = 30000 ;
49+ private volatile long timeoutPerShutdownPhase = 30000 ;
5150
5251 private volatile boolean running ;
5352
5453 private volatile ConfigurableListableBeanFactory beanFactory ;
5554
5655
5756 /**
58- * Specify the maximum time allotted for the shutdown of any group of
59- * SmartLifecycle beans (those with the same 'order ' value). The default
60- * value is 30 seconds.
57+ * Specify the maximum time allotted for the shutdown of any phase
58+ * (group of SmartLifecycle beans with the same 'phase ' value).
59+ * The default value is 30 seconds.
6160 */
62- public void setShutdownGroupTimeout (long shutdownGroupTimeout ) {
63- this .shutdownGroupTimeout = shutdownGroupTimeout ;
61+ public void setTimeoutPerShutdownPhase (long timeoutPerShutdownPhase ) {
62+ this .timeoutPerShutdownPhase = timeoutPerShutdownPhase ;
6463 }
6564
6665 public void setBeanFactory (BeanFactory beanFactory ) {
@@ -77,58 +76,84 @@ public boolean isRunning() {
7776 return this .running ;
7877 }
7978
79+ /**
80+ * Start all registered beans that implement Lifecycle and are
81+ * <i>not</i> already running. Any bean that implements SmartLifecycle
82+ * will be started within its 'phase', and all phases will be ordered
83+ * from lowest to highest value. All beans that do not implement
84+ * SmartLifecycle will be started in the default phase 0. A bean
85+ * declared as a dependency of another bean will be started before
86+ * the dependent bean regardless of the declared phase.
87+ */
8088 public void start () {
81- Map <String , Lifecycle > lifecycleBeans = getLifecycleBeans ();
82- for (String beanName : new LinkedHashSet <String >(lifecycleBeans .keySet ())) {
83- doStart (lifecycleBeans , beanName );
84- }
85- this .running = true ;
89+ this .startBeans (false );
8690 }
8791
92+ /**
93+ * Stop all registered beans that implement Lifecycle and <i>are</i>
94+ * currently running. Any bean that implements SmartLifecycle
95+ * will be stopped within its 'phase', and all phases will be ordered
96+ * from highest to lowest value. All beans that do not implement
97+ * SmartLifecycle will be stopped in the default phase 0. A bean
98+ * declared as dependent on another bean will be stopped before
99+ * the dependency bean regardless of the declared phase.
100+ */
88101 public void stop () {
89102 Map <String , Lifecycle > lifecycleBeans = getLifecycleBeans ();
90- Map <Integer , ShutdownGroup > shutdownGroups = new HashMap <Integer , ShutdownGroup >();
103+ Map <Integer , LifecycleGroup > phases = new HashMap <Integer , LifecycleGroup >();
91104 for (Map .Entry <String , Lifecycle > entry : lifecycleBeans .entrySet ()) {
92105 Lifecycle lifecycle = entry .getValue ();
93- int shutdownOrder = getShutdownOrder (lifecycle );
94- ShutdownGroup group = shutdownGroups .get (shutdownOrder );
106+ int shutdownOrder = getPhase (lifecycle );
107+ LifecycleGroup group = phases .get (shutdownOrder );
95108 if (group == null ) {
96- group = new ShutdownGroup (shutdownOrder , this .shutdownGroupTimeout , lifecycleBeans );
97- shutdownGroups .put (shutdownOrder , group );
109+ group = new LifecycleGroup (shutdownOrder , this .timeoutPerShutdownPhase , lifecycleBeans );
110+ phases .put (shutdownOrder , group );
98111 }
99112 group .add (entry .getKey (), lifecycle );
100113 }
101- if (shutdownGroups .size () > 0 ) {
102- List <Integer > keys = new ArrayList <Integer >(shutdownGroups .keySet ());
103- Collections .sort (keys );
114+ if (phases .size () > 0 ) {
115+ List <Integer > keys = new ArrayList <Integer >(phases .keySet ());
116+ Collections .sort (keys , Collections . reverseOrder () );
104117 for (Integer key : keys ) {
105- shutdownGroups .get (key ).shutdown ();
118+ phases .get (key ).stop ();
106119 }
107120 }
108121 this .running = false ;
109122 }
110123
111124 public void onRefresh () {
112- Map <String , SmartLifecycle > lifecycleBeans = getSmartLifecycleBeans ();
113- for (String beanName : new LinkedHashSet <String >(lifecycleBeans .keySet ())) {
114- SmartLifecycle bean = lifecycleBeans .get (beanName );
115- if (bean != null && bean .isAutoStartup ()) {
116- String [] dependenciesForBean = this .beanFactory .getDependenciesForBean (beanName );
117- for (String dependency : dependenciesForBean ) {
118- doStart (lifecycleBeans , dependency );
119- }
120- if (!bean .isRunning ()) {
121- bean .start ();
122- }
123- lifecycleBeans .remove (beanName );
124- }
125- }
125+ this .startBeans (true );
126126 }
127127
128128 public void onClose () {
129129 stop ();
130130 }
131131
132+ private void startBeans (boolean autoStartupOnly ) {
133+ Map <String , Lifecycle > lifecycleBeans = getLifecycleBeans ();
134+ Map <Integer , LifecycleGroup > phases = new HashMap <Integer , LifecycleGroup >();
135+ for (Map .Entry <String , ? extends Lifecycle > entry : lifecycleBeans .entrySet ()) {
136+ Lifecycle lifecycle = entry .getValue ();
137+ if (!autoStartupOnly || (lifecycle instanceof SmartLifecycle && ((SmartLifecycle ) lifecycle ).isAutoStartup ())) {
138+ int phase = getPhase (lifecycle );
139+ LifecycleGroup group = phases .get (phase );
140+ if (group == null ) {
141+ group = new LifecycleGroup (phase , this .timeoutPerShutdownPhase , lifecycleBeans );
142+ phases .put (phase , group );
143+ }
144+ group .add (entry .getKey (), lifecycle );
145+ }
146+ }
147+ if (phases .size () > 0 ) {
148+ List <Integer > keys = new ArrayList <Integer >(phases .keySet ());
149+ Collections .sort (keys );
150+ for (Integer key : keys ) {
151+ phases .get (key ).start ();
152+ }
153+ }
154+ this .running = true ;
155+ }
156+
132157 /**
133158 * Start the specified bean as part of the given set of Lifecycle beans,
134159 * making sure that any beans that it depends on are started first.
@@ -155,7 +180,7 @@ private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String bea
155180 * @param lifecycleBeans Map with bean name as key and Lifecycle instance as value
156181 * @param beanName the name of the bean to stop
157182 */
158- private void doStop (Map <String , Lifecycle > lifecycleBeans , String beanName , final CountDownLatch latch ) {
183+ private void doStop (Map <String , ? extends Lifecycle > lifecycleBeans , String beanName , final CountDownLatch latch ) {
159184 Lifecycle bean = lifecycleBeans .get (beanName );
160185 if (bean != null ) {
161186 String [] dependentBeans = this .beanFactory .getDependentBeans (beanName );
@@ -194,44 +219,31 @@ private Map<String, Lifecycle> getLifecycleBeans() {
194219 return beans ;
195220 }
196221
197- private Map <String , SmartLifecycle > getSmartLifecycleBeans () {
198- String [] beanNames = beanFactory .getSingletonNames ();
199- Map <String , SmartLifecycle > beans = new LinkedHashMap <String , SmartLifecycle >();
200- for (String beanName : beanNames ) {
201- Object bean = beanFactory .getSingleton (beanName );
202- if (bean instanceof SmartLifecycle ) {
203- beans .put (beanName , (SmartLifecycle ) bean );
204- }
205- }
206- return beans ;
207- }
208-
209-
210- private static int getShutdownOrder (Lifecycle bean ) {
222+ private static int getPhase (Lifecycle bean ) {
211223 return (bean instanceof SmartLifecycle ) ?
212- ((SmartLifecycle ) bean ).getShutdownOrder () : Integer . MAX_VALUE ;
224+ ((SmartLifecycle ) bean ).getPhase () : 0 ;
213225 }
214226
215227
216228 /**
217- * Helper class for maintaining a group of Lifecycle beans that should be shutdown
218- * together based on their 'shutdownOrder ' value (or the default MAX_INTEGER value).
229+ * Helper class for maintaining a group of Lifecycle beans that should be started
230+ * and stopped together based on their 'phase ' value (or the default value of 0).
219231 */
220- private class ShutdownGroup {
232+ private class LifecycleGroup {
221233
222- private final List <ShutdownGroupMember > members = new ArrayList <ShutdownGroupMember >();
234+ private final List <LifecycleGroupMember > members = new ArrayList <LifecycleGroupMember >();
223235
224- private Map <String , Lifecycle > lifecycleBeans = getLifecycleBeans ();
236+ private Map <String , ? extends Lifecycle > lifecycleBeans = getLifecycleBeans ();
225237
226238 private volatile int smartMemberCount ;
227239
228- private final int order ;
240+ private final int phase ;
229241
230242 private final long timeout ;
231243
232244
233- ShutdownGroup (int order , long timeout , Map <String , Lifecycle > lifecycleBeans ) {
234- this .order = order ;
245+ LifecycleGroup (int phase , long timeout , Map <String , ? extends Lifecycle > lifecycleBeans ) {
246+ this .phase = phase ;
235247 this .timeout = timeout ;
236248 this .lifecycleBeans = lifecycleBeans ;
237249 }
@@ -240,16 +252,28 @@ void add(String name, Lifecycle bean) {
240252 if (bean instanceof SmartLifecycle ) {
241253 this .smartMemberCount ++;
242254 }
243- this .members .add (new ShutdownGroupMember (name , bean ));
255+ this .members .add (new LifecycleGroupMember (name , bean ));
244256 }
245257
246- void shutdown () {
258+ void start () {
247259 if (members .size () == 0 ) {
248260 return ;
249261 }
250262 Collections .sort (members );
263+ for (LifecycleGroupMember member : members ) {
264+ if (lifecycleBeans .containsKey (member .name )) {
265+ doStart (lifecycleBeans , member .name );
266+ }
267+ }
268+ }
269+
270+ void stop () {
271+ if (members .size () == 0 ) {
272+ return ;
273+ }
274+ Collections .sort (members , Collections .reverseOrder ());
251275 final CountDownLatch latch = new CountDownLatch (this .smartMemberCount );
252- for (ShutdownGroupMember member : members ) {
276+ for (LifecycleGroupMember member : members ) {
253277 if (lifecycleBeans .containsKey (member .name )) {
254278 doStop (lifecycleBeans , member .name , latch );
255279 }
@@ -262,8 +286,8 @@ else if (member.bean instanceof SmartLifecycle) {
262286 latch .await (this .timeout , TimeUnit .MILLISECONDS );
263287 if (latch .getCount () != 0 ) {
264288 if (logger .isWarnEnabled ()) {
265- logger .warn ("failed to shutdown beans with order " +
266- this .order + " within timeout of " + this .timeout );
289+ logger .warn ("failed to shutdown beans with phase value " +
290+ this .phase + " within timeout of " + this .timeout );
267291 }
268292 }
269293 }
@@ -274,20 +298,20 @@ else if (member.bean instanceof SmartLifecycle) {
274298 }
275299
276300
277- private static class ShutdownGroupMember implements Comparable <ShutdownGroupMember > {
301+ private static class LifecycleGroupMember implements Comparable <LifecycleGroupMember > {
278302
279- private String name ;
303+ private final String name ;
280304
281- private Lifecycle bean ;
305+ private final Lifecycle bean ;
282306
283- ShutdownGroupMember (String name , Lifecycle bean ) {
307+ LifecycleGroupMember (String name , Lifecycle bean ) {
284308 this .name = name ;
285309 this .bean = bean ;
286310 }
287311
288- public int compareTo (ShutdownGroupMember other ) {
289- int thisOrder = getShutdownOrder (this .bean );
290- int otherOrder = getShutdownOrder (other .bean );
312+ public int compareTo (LifecycleGroupMember other ) {
313+ int thisOrder = getPhase (this .bean );
314+ int otherOrder = getPhase (other .bean );
291315 return (thisOrder == otherOrder ) ? 0 : (thisOrder < otherOrder ) ? -1 : 1 ;
292316 }
293317 }
0 commit comments