27
27
import java .util .Map ;
28
28
import java .util .Set ;
29
29
import java .util .concurrent .atomic .AtomicBoolean ;
30
+ import java .util .concurrent .locks .Lock ;
31
+ import java .util .concurrent .locks .ReentrantLock ;
30
32
31
33
import org .apache .commons .logging .Log ;
32
34
import org .apache .commons .logging .LogFactory ;
@@ -203,8 +205,8 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
203
205
/** Flag that indicates whether this context has been closed already. */
204
206
private final AtomicBoolean closed = new AtomicBoolean ();
205
207
206
- /** Synchronization monitor for the "refresh" and "destroy". */
207
- private final Object startupShutdownMonitor = new Object ();
208
+ /** Synchronization lock for the "refresh" and "destroy". */
209
+ private final Lock startupShutdownLock = new ReentrantLock ();
208
210
209
211
/** Reference to the JVM shutdown hook, if registered. */
210
212
@ Nullable
@@ -576,7 +578,8 @@ public Collection<ApplicationListener<?>> getApplicationListeners() {
576
578
577
579
@ Override
578
580
public void refresh () throws BeansException , IllegalStateException {
579
- synchronized (this .startupShutdownMonitor ) {
581
+ this .startupShutdownLock .lock ();
582
+ try {
580
583
StartupStep contextRefresh = this .applicationStartup .start ("spring.context.refresh" );
581
584
582
585
// Prepare this context for refreshing.
@@ -624,6 +627,7 @@ public void refresh() throws BeansException, IllegalStateException {
624
627
logger .warn ("Exception encountered during context initialization - " +
625
628
"cancelling refresh attempt: " + ex );
626
629
}
630
+
627
631
// Destroy already created singletons to avoid dangling resources.
628
632
destroyBeans ();
629
633
@@ -638,19 +642,18 @@ public void refresh() throws BeansException, IllegalStateException {
638
642
contextRefresh .end ();
639
643
}
640
644
}
645
+ finally {
646
+ this .startupShutdownLock .unlock ();
647
+ }
641
648
}
642
649
643
650
/**
644
651
* Prepare this context for refreshing, setting its startup date and
645
652
* active flag as well as performing any initialization of property sources.
646
653
*/
647
654
protected void prepareRefresh () {
648
- this .startupDate = System .currentTimeMillis ();
649
-
650
- // Remove shutdown hook during refresh phase.
651
- removeShutdownHook ();
652
-
653
655
// Switch to active.
656
+ this .startupDate = System .currentTimeMillis ();
654
657
this .closed .set (false );
655
658
this .active .set (true );
656
659
@@ -970,9 +973,6 @@ protected void finishRefresh() {
970
973
971
974
// Publish the final event.
972
975
publishEvent (new ContextRefreshedEvent (this ));
973
-
974
- // Restore shutdown hook if registered before.
975
- restoreShutdownHook ();
976
976
}
977
977
978
978
/**
@@ -1022,37 +1022,20 @@ public void registerShutdownHook() {
1022
1022
this .shutdownHook = new Thread (SHUTDOWN_HOOK_THREAD_NAME ) {
1023
1023
@ Override
1024
1024
public void run () {
1025
- synchronized (startupShutdownMonitor ) {
1026
- doClose ();
1025
+ if (startupShutdownLock .tryLock ()) {
1026
+ try {
1027
+ doClose ();
1028
+ }
1029
+ finally {
1030
+ startupShutdownLock .unlock ();
1031
+ }
1027
1032
}
1028
1033
}
1029
1034
};
1030
1035
Runtime .getRuntime ().addShutdownHook (this .shutdownHook );
1031
1036
}
1032
1037
}
1033
1038
1034
- private void removeShutdownHook () {
1035
- if (this .shutdownHook != null ) {
1036
- try {
1037
- Runtime .getRuntime ().removeShutdownHook (this .shutdownHook );
1038
- }
1039
- catch (IllegalStateException ex ) {
1040
- // ignore - VM is already shutting down
1041
- }
1042
- }
1043
- }
1044
-
1045
- private void restoreShutdownHook () {
1046
- if (this .shutdownHook != null ) {
1047
- try {
1048
- Runtime .getRuntime ().addShutdownHook (this .shutdownHook );
1049
- }
1050
- catch (IllegalStateException | IllegalArgumentException ex ) {
1051
- // ignore - VM is already shutting down or hook already registered
1052
- }
1053
- }
1054
- }
1055
-
1056
1039
/**
1057
1040
* Close this application context, destroying all beans in its bean factory.
1058
1041
* <p>Delegates to {@code doClose()} for the actual closing procedure.
@@ -1062,12 +1045,23 @@ private void restoreShutdownHook() {
1062
1045
*/
1063
1046
@ Override
1064
1047
public void close () {
1065
- synchronized (this .startupShutdownMonitor ) {
1066
- // If we registered a JVM shutdown hook, we don't need it anymore now:
1067
- // We're already explicitly closing the context.
1068
- removeShutdownHook ();
1069
-
1070
- doClose ();
1048
+ if (this .startupShutdownLock .tryLock ()) {
1049
+ try {
1050
+ doClose ();
1051
+ // If we registered a JVM shutdown hook, we don't need it anymore now:
1052
+ // We've already explicitly closed the context.
1053
+ if (this .shutdownHook != null ) {
1054
+ try {
1055
+ Runtime .getRuntime ().removeShutdownHook (this .shutdownHook );
1056
+ }
1057
+ catch (IllegalStateException ex ) {
1058
+ // ignore - VM is already shutting down
1059
+ }
1060
+ }
1061
+ }
1062
+ finally {
1063
+ this .startupShutdownLock .unlock ();
1064
+ }
1071
1065
}
1072
1066
}
1073
1067
0 commit comments