diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java index 2fd9a3f3459..b43513de535 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java @@ -207,7 +207,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe private int startupDelay = 0; - private int phase = Integer.MAX_VALUE; + private int phase = DEFAULT_PHASE; private boolean exposeSchedulerInRepository = false; @@ -796,12 +796,6 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe } } - @Override - public void stop(Runnable callback) throws SchedulingException { - stop(); - callback.run(); - } - @Override public boolean isRunning() throws SchedulingException { if (this.scheduler != null) { diff --git a/spring-context/src/main/java/org/springframework/context/Lifecycle.java b/spring-context/src/main/java/org/springframework/context/Lifecycle.java index 16060116bb7..3cda24bbfe5 100644 --- a/spring-context/src/main/java/org/springframework/context/Lifecycle.java +++ b/spring-context/src/main/java/org/springframework/context/Lifecycle.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,10 +34,11 @@ package org.springframework.context; * restricting the visibility of activity-controlled components to the Lifecycle * interface. * - *

Note that the Lifecycle interface is only supported on top-level singleton - * beans. On any other component, the Lifecycle interface will remain undetected - * and hence ignored. Also, note that the extended {@link SmartLifecycle} interface - * provides integration with the application context's startup and shutdown phases. + *

Note that the present {@code Lifecycle} interface is only supported on + * top-level singleton beans. On any other component, the {@code Lifecycle} + * interface will remain undetected and hence ignored. Also, note that the extended + * {@link SmartLifecycle} interface provides sophisticated integration with the + * application context's startup and shutdown phases. * * @author Juergen Hoeller * @since 2.0 @@ -61,11 +62,12 @@ public interface Lifecycle { * Stop this component, typically in a synchronous fashion, such that the component is * fully stopped upon return of this method. Consider implementing {@link SmartLifecycle} * and its {@code stop(Runnable)} variant when asynchronous stop behavior is necessary. - *

Note that this stop notification is not guaranteed to come before destruction: On - * regular shutdown, {@code Lifecycle} beans will first receive a stop notification before - * the general destruction callbacks are being propagated; however, on hot refresh during a - * context's lifetime or on aborted refresh attempts, only destroy methods will be called. - *

Should not throw an exception if the component isn't started yet. + *

Note that this stop notification is not guaranteed to come before destruction: + * On regular shutdown, {@code Lifecycle} beans will first receive a stop notification + * before the general destruction callbacks are being propagated; however, on hot + * refresh during a context's lifetime or on aborted refresh attempts, a given bean's + * destroy method will be called without any consideration of stop signals upfront. + *

Should not throw an exception if the component is not running (not started yet). *

In the case of a container, this will propagate the stop signal to all components * that apply. * @see SmartLifecycle#stop(Runnable) diff --git a/spring-context/src/main/java/org/springframework/context/SmartLifecycle.java b/spring-context/src/main/java/org/springframework/context/SmartLifecycle.java index 1ae2c12e9de..b3e5a28bced 100644 --- a/spring-context/src/main/java/org/springframework/context/SmartLifecycle.java +++ b/spring-context/src/main/java/org/springframework/context/SmartLifecycle.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,43 +23,56 @@ package org.springframework.context; * be started at the time of a context refresh. The callback-accepting * {@link #stop(Runnable)} method is useful for objects that have an asynchronous * shutdown process. Any implementation of this interface must invoke the - * callback's run() method upon shutdown completion to avoid unnecessary delays - * in the overall ApplicationContext shutdown. + * callback's {@code run()} method upon shutdown completion to avoid unnecessary + * delays in the overall ApplicationContext shutdown. * *

This interface extends {@link Phased}, and the {@link #getPhase()} method's * return value indicates the phase within which this Lifecycle component should - * be started and stopped. The startup process begins with the lowest - * phase value and ends with the highest phase value (Integer.MIN_VALUE - * is the lowest possible, and Integer.MAX_VALUE is the highest possible). The - * shutdown process will apply the reverse order. Any components with the + * be started and stopped. The startup process begins with the lowest phase + * value and ends with the highest phase value ({@code Integer.MIN_VALUE} + * is the lowest possible, and {@code Integer.MAX_VALUE} is the highest possible). + * The shutdown process will apply the reverse order. Any components with the * same value will be arbitrarily ordered within the same phase. * - *

Example: if component B depends on component A having already started, then - * component A should have a lower phase value than component B. During the - * shutdown process, component B would be stopped before component A. + *

Example: if component B depends on component A having already started, + * then component A should have a lower phase value than component B. During + * the shutdown process, component B would be stopped before component A. * - *

Any explicit "depends-on" relationship will take precedence over - * the phase order such that the dependent bean always starts after its - * dependency and always stops before its dependency. + *

Any explicit "depends-on" relationship will take precedence over the phase + * order such that the dependent bean always starts after its dependency and + * always stops before its dependency. * - *

Any Lifecycle components within the context that do not also implement - * SmartLifecycle will be treated as if they have a phase value of 0. That - * way a SmartLifecycle implementation may start before those Lifecycle - * components if it has a negative phase value, or it may start after - * those components if it has a positive phase value. + *

Any {@code Lifecycle} components within the context that do not also + * implement {@code SmartLifecycle} will be treated as if they have a phase + * value of 0. That way a {@code SmartLifecycle} implementation may start + * before those {@code Lifecycle} components if it has a negative phase value, + * or it may start after those components if it has a positive phase value. * - *

Note that, due to the auto-startup support in SmartLifecycle, - * a SmartLifecycle bean instance will get initialized on startup of the - * application context in any case. As a consequence, the bean definition - * lazy-init flag has very limited actual effect on SmartLifecycle beans. + *

Note that, due to the auto-startup support in {@code SmartLifecycle}, a + * {@code SmartLifecycle} bean instance will usually get initialized on startup + * of the application context in any case. As a consequence, the bean definition + * lazy-init flag has very limited actual effect on {@code SmartLifecycle} beans. * * @author Mark Fisher + * @author Juergen Hoeller * @since 3.0 * @see LifecycleProcessor * @see ConfigurableApplicationContext */ public interface SmartLifecycle extends Lifecycle, Phased { + /** + * The default phase for {@code SmartLifecycle}: {@code Integer.MAX_VALUE}. + *

This is different from the common phase 0 associated with regular + * {@link Lifecycle} implementations, putting the typically auto-started + * {@code SmartLifecycle} beans into a separate later shutdown phase. + * @since 5.1 + * @see #getPhase() + * @see org.springframework.context.support.DefaultLifecycleProcessor#getPhase(Lifecycle) + */ + int DEFAULT_PHASE = Integer.MAX_VALUE; + + /** * Returns {@code true} if this {@code Lifecycle} component should get * started automatically by the container at the time that the containing @@ -67,12 +80,15 @@ public interface SmartLifecycle extends Lifecycle, Phased { *

A value of {@code false} indicates that the component is intended to * be started through an explicit {@link #start()} call instead, analogous * to a plain {@link Lifecycle} implementation. + *

The default implementation returns {@code true}. * @see #start() * @see #getPhase() * @see LifecycleProcessor#onRefresh() * @see ConfigurableApplicationContext#refresh() */ - boolean isAutoStartup(); + default boolean isAutoStartup() { + return true; + } /** * Indicates that a Lifecycle component must stop if it is currently running. @@ -84,9 +100,30 @@ public interface SmartLifecycle extends Lifecycle, Phased { * {@code stop} method; i.e. {@link Lifecycle#stop()} will not be called for * {@code SmartLifecycle} implementations unless explicitly delegated to within * the implementation of this method. + *

The default implementation delegates to {@link #stop()} and immediately + * triggers the given callback in the calling thread. Note that there is no + * synchronization between the two, so custom implementations may at least + * want to put the same steps within their common lifecycle monitor (if any). * @see #stop() * @see #getPhase() */ - void stop(Runnable callback); + default void stop(Runnable callback) { + stop(); + callback.run(); + } + + /** + * Return the phase that this lifecycle object is supposed to run in. + *

The default implementation returns {@link #DEFAULT_PHASE} in order to + * let stop callbacks execute after regular {@code Lifecycle} implementations. + * @see #isAutoStartup() + * @see #start() + * @see #stop(Runnable) + * @see org.springframework.context.support.DefaultLifecycleProcessor#getPhase(Lifecycle) + */ + @Override + default int getPhase() { + return DEFAULT_PHASE; + } } diff --git a/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java b/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java index b16e13495cb..1ae6d02ba73 100644 --- a/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java @@ -195,11 +195,11 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor Map lifecycleBeans = getLifecycleBeans(); Map phases = new HashMap<>(); lifecycleBeans.forEach((beanName, bean) -> { - int shutdownOrder = getPhase(bean); - LifecycleGroup group = phases.get(shutdownOrder); + int shutdownPhase = getPhase(bean); + LifecycleGroup group = phases.get(shutdownPhase); if (group == null) { - group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans, false); - phases.put(shutdownOrder, group); + group = new LifecycleGroup(shutdownPhase, this.timeoutPerShutdownPhase, lifecycleBeans, false); + phases.put(shutdownPhase, group); } group.add(beanName, bean); }); @@ -302,11 +302,11 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor /** * Determine the lifecycle phase of the given bean. - *

The default implementation checks for the {@link Phased} interface. - * Can be overridden to apply other/further policies. + *

The default implementation checks for the {@link Phased} interface, using + * a default of 0 otherwise. Can be overridden to apply other/further policies. * @param bean the bean to introspect - * @return the phase an integer value. The suggested default is 0. - * @see Phased + * @return the phase (an integer value) + * @see Phased#getPhase() * @see SmartLifecycle */ protected int getPhase(Lifecycle bean) { @@ -412,9 +412,9 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor @Override public int compareTo(LifecycleGroupMember other) { - int thisOrder = getPhase(this.bean); - int otherOrder = getPhase(other.bean); - return Integer.compare(thisOrder, otherOrder); + int thisPhase = getPhase(this.bean); + int otherPhase = getPhase(other.bean); + return Integer.compare(thisPhase, otherPhase); } } diff --git a/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java b/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java index 018bd6374ce..3d0b4b7069d 100644 --- a/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java +++ b/spring-jms/src/main/java/org/springframework/jms/config/JmsListenerEndpointRegistry.java @@ -66,7 +66,7 @@ public class JmsListenerEndpointRegistry implements DisposableBean, SmartLifecyc private final Map listenerContainers = new ConcurrentHashMap<>(); - private int phase = Integer.MAX_VALUE; + private int phase = DEFAULT_PHASE; @Nullable private ApplicationContext applicationContext; @@ -198,11 +198,6 @@ public class JmsListenerEndpointRegistry implements DisposableBean, SmartLifecyc return this.phase; } - @Override - public boolean isAutoStartup() { - return true; - } - @Override public void start() { for (MessageListenerContainer listenerContainer : getListenerContainers()) { diff --git a/spring-jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java b/spring-jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java index 3e9f1274c08..4bb9224b001 100644 --- a/spring-jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java +++ b/spring-jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java @@ -66,7 +66,7 @@ public abstract class AbstractJmsListeningContainer extends JmsDestinationAccess private boolean autoStartup = true; - private int phase = Integer.MAX_VALUE; + private int phase = DEFAULT_PHASE; @Nullable private String beanName; @@ -319,12 +319,6 @@ public abstract class AbstractJmsListeningContainer extends JmsDestinationAccess } } - @Override - public void stop(Runnable callback) { - stop(); - callback.run(); - } - /** * Notify all invoker tasks and stop the shared Connection, if any. * @throws JMSException if thrown by JMS API methods diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java index 256f6d50fd5..c0d899d048e 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java @@ -268,16 +268,6 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan } - @Override - public boolean isAutoStartup() { - return true; - } - - @Override - public int getPhase() { - return Integer.MAX_VALUE; - } - @Override public final void start() { synchronized (this.lifecycleMonitor) { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/AbstractBrokerMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/AbstractBrokerMessageHandler.java index 0e52ccea042..db8aaf5d82f 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/AbstractBrokerMessageHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/broker/AbstractBrokerMessageHandler.java @@ -173,11 +173,6 @@ public abstract class AbstractBrokerMessageHandler return this.autoStartup; } - @Override - public int getPhase() { - return Integer.MAX_VALUE; - } - @Override public void start() { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationMessageHandler.java index 2644e81037b..26623d5f187 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationMessageHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/user/UserDestinationMessageHandler.java @@ -147,16 +147,6 @@ public class UserDestinationMessageHandler implements MessageHandler, SmartLifec } - @Override - public int getPhase() { - return Integer.MAX_VALUE; - } - - @Override - public boolean isAutoStartup() { - return true; - } - @Override public final void start() { synchronized (this.lifecycleMonitor) { diff --git a/spring-tx/src/main/java/org/springframework/jca/endpoint/GenericMessageEndpointManager.java b/spring-tx/src/main/java/org/springframework/jca/endpoint/GenericMessageEndpointManager.java index badef43b603..495fc99e616 100644 --- a/spring-tx/src/main/java/org/springframework/jca/endpoint/GenericMessageEndpointManager.java +++ b/spring-tx/src/main/java/org/springframework/jca/endpoint/GenericMessageEndpointManager.java @@ -159,7 +159,7 @@ public class GenericMessageEndpointManager implements SmartLifecycle, Initializi private boolean autoStartup = true; - private int phase = Integer.MAX_VALUE; + private int phase = DEFAULT_PHASE; private volatile boolean running = false; diff --git a/spring-web/src/main/java/org/springframework/http/client/reactive/JettyClientHttpConnector.java b/spring-web/src/main/java/org/springframework/http/client/reactive/JettyClientHttpConnector.java index 54e38bcba61..115c6abc736 100644 --- a/spring-web/src/main/java/org/springframework/http/client/reactive/JettyClientHttpConnector.java +++ b/spring-web/src/main/java/org/springframework/http/client/reactive/JettyClientHttpConnector.java @@ -71,21 +71,6 @@ public class JettyClientHttpConnector implements ClientHttpConnector, SmartLifec } - @Override - public int getPhase() { - return Integer.MAX_VALUE; - } - - @Override - public boolean isAutoStartup() { - return true; - } - - @Override - public boolean isRunning() { - return this.httpClient.isRunning(); - } - @Override public void start() { try { @@ -108,9 +93,8 @@ public class JettyClientHttpConnector implements ClientHttpConnector, SmartLifec } @Override - public void stop(Runnable callback) { - stop(); - callback.run(); + public boolean isRunning() { + return this.httpClient.isRunning(); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/ConnectionManagerSupport.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/ConnectionManagerSupport.java index f5638ea8337..df0763701c7 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/ConnectionManagerSupport.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/ConnectionManagerSupport.java @@ -42,7 +42,7 @@ public abstract class ConnectionManagerSupport implements SmartLifecycle { private boolean autoStartup = false; - private int phase = Integer.MAX_VALUE; + private int phase = DEFAULT_PHASE; private volatile boolean running = false; diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SubProtocolWebSocketHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SubProtocolWebSocketHandler.java index d0b763fc49f..06f92479762 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SubProtocolWebSocketHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SubProtocolWebSocketHandler.java @@ -254,16 +254,6 @@ public class SubProtocolWebSocketHandler } - @Override - public boolean isAutoStartup() { - return true; - } - - @Override - public int getPhase() { - return Integer.MAX_VALUE; - } - @Override public final void start() { Assert.isTrue(this.defaultProtocolHandler != null || !this.protocolHandlers.isEmpty(), "No handlers"); diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/WebSocketStompClient.java b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/WebSocketStompClient.java index 725d7d5fb55..50039c658a3 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/messaging/WebSocketStompClient.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/messaging/WebSocketStompClient.java @@ -79,7 +79,7 @@ public class WebSocketStompClient extends StompClientSupport implements SmartLif private boolean autoStartup = true; - private int phase = Integer.MAX_VALUE; + private int phase = DEFAULT_PHASE; private volatile boolean running = false; @@ -194,12 +194,6 @@ public class WebSocketStompClient extends StompClientSupport implements SmartLif } } - @Override - public void stop(Runnable callback) { - stop(); - callback.run(); - } - @Override public boolean isRunning() { return this.running; @@ -396,7 +390,10 @@ public class WebSocketStompClient extends StompClientSupport implements SmartLif } private void updateLastWriteTime() { - this.lastWriteTime = (this.lastWriteTime != -1 ? System.currentTimeMillis() : -1); + long lastWriteTime = this.lastWriteTime; + if (lastWriteTime != -1) { + this.lastWriteTime = System.currentTimeMillis(); + } } @Override diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/support/WebSocketHandlerMapping.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/support/WebSocketHandlerMapping.java index 2cd4eb9d53b..aaa56363b22 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/support/WebSocketHandlerMapping.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/support/WebSocketHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,15 +46,6 @@ public class WebSocketHandlerMapping extends SimpleUrlHandlerMapping implements } } - @Override - public boolean isAutoStartup() { - return true; - } - - @Override - public int getPhase() { - return Integer.MAX_VALUE; - } @Override public void start() { @@ -80,12 +71,6 @@ public class WebSocketHandlerMapping extends SimpleUrlHandlerMapping implements } } - @Override - public void stop(Runnable callback) { - stop(); - callback.run(); - } - @Override public boolean isRunning() { return this.running;