1
1
/*
2
- * Copyright 2002-2017 the original author or authors.
2
+ * Copyright 2002-2018 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
36
36
import java .util .concurrent .Executors ;
37
37
import java .util .concurrent .LinkedBlockingDeque ;
38
38
import java .util .concurrent .Semaphore ;
39
+ import java .util .concurrent .ThreadFactory ;
39
40
import java .util .concurrent .TimeUnit ;
40
41
import java .util .concurrent .TimeoutException ;
41
42
import java .util .concurrent .atomic .AtomicBoolean ;
56
57
import org .springframework .context .event .ContextClosedEvent ;
57
58
import org .springframework .jmx .export .annotation .ManagedAttribute ;
58
59
import org .springframework .jmx .export .annotation .ManagedResource ;
60
+ import org .springframework .scheduling .concurrent .CustomizableThreadFactory ;
59
61
import org .springframework .util .Assert ;
60
62
import org .springframework .util .ObjectUtils ;
61
63
import org .springframework .util .StringUtils ;
92
94
* @author Gary Russell
93
95
* @author Artem Bilan
94
96
* @author Steve Powell
97
+ * @author Will Droste
95
98
*/
96
99
@ ManagedResource
97
100
public class CachingConnectionFactory extends AbstractConnectionFactory
98
101
implements InitializingBean , ShutdownListener , ApplicationContextAware , ApplicationListener <ContextClosedEvent >,
99
- PublisherCallbackChannelConnectionFactory {
102
+ PublisherCallbackChannelConnectionFactory {
100
103
101
104
private static final int DEFAULT_CHANNEL_CACHE_SIZE = 25 ;
102
105
106
+ private static final String DEFAULT_DEFERRED_POOL_PREFIX = "spring-rabbit-deferred-pool-" ;
107
+
108
+ /**
109
+ * Create a unique ID for the pool
110
+ */
111
+ private static final AtomicInteger threadPoolId = new AtomicInteger ();
112
+
103
113
private static final Set <String > txStarts = new HashSet <String >(Arrays .asList ("basicPublish" , "basicAck" , "basicNack" ,
104
114
"basicReject" ));
105
115
@@ -122,10 +132,10 @@ public enum CacheMode {
122
132
new HashSet <ChannelCachingConnectionProxy >();
123
133
124
134
private final Map <ChannelCachingConnectionProxy , LinkedList <ChannelProxy >>
125
- allocatedConnectionNonTransactionalChannels = new HashMap <ChannelCachingConnectionProxy , LinkedList <ChannelProxy >>();
135
+ allocatedConnectionNonTransactionalChannels = new HashMap <ChannelCachingConnectionProxy , LinkedList <ChannelProxy >>();
126
136
127
137
private final Map <ChannelCachingConnectionProxy , LinkedList <ChannelProxy >>
128
- allocatedConnectionTransactionalChannels = new HashMap <ChannelCachingConnectionProxy , LinkedList <ChannelProxy >>();
138
+ allocatedConnectionTransactionalChannels = new HashMap <ChannelCachingConnectionProxy , LinkedList <ChannelProxy >>();
129
139
130
140
private final BlockingDeque <ChannelCachingConnectionProxy > idleConnections =
131
141
new LinkedBlockingDeque <ChannelCachingConnectionProxy >();
@@ -166,12 +176,15 @@ public enum CacheMode {
166
176
167
177
private volatile ConditionalExceptionLogger closeExceptionLogger = new DefaultChannelCloseLogger ();
168
178
169
- /** Synchronization monitor for the shared Connection */
179
+ /**
180
+ * Synchronization monitor for the shared Connection
181
+ */
170
182
private final Object connectionMonitor = new Object ();
171
183
172
- /** Executor used for deferred close if no explicit executor set. */
173
- private final ExecutorService deferredCloseExecutor = Executors .newCachedThreadPool ();
174
-
184
+ /**
185
+ * Executor used for deferred close if no explicit executor set.
186
+ */
187
+ private ExecutorService deferredCloseExecutor ;
175
188
176
189
/**
177
190
* Create a new CachingConnectionFactory initializing the hostname to be the value returned from
@@ -406,7 +419,7 @@ private Channel getChannel(ChannelCachingConnectionProxy connection, boolean tra
406
419
}
407
420
if (logger .isDebugEnabled ()) {
408
421
logger .debug (
409
- "Acquired permit for " + connection + ", remaining:" + checkoutPermits .availablePermits ());
422
+ "Acquired permit for " + connection + ", remaining:" + checkoutPermits .availablePermits ());
410
423
}
411
424
}
412
425
catch (InterruptedException e ) {
@@ -486,7 +499,7 @@ private Channel getChannel(ChannelCachingConnectionProxy connection, boolean tra
486
499
checkoutPermits .release ();
487
500
if (logger .isDebugEnabled ()) {
488
501
logger .debug ("Could not get channel; released permit for " + connection + ", remaining:"
489
- + checkoutPermits .availablePermits ());
502
+ + checkoutPermits .availablePermits ());
490
503
}
491
504
}
492
505
throw e ;
@@ -692,7 +705,9 @@ public final void destroy() {
692
705
resetConnection ();
693
706
if (this .contextStopped ) {
694
707
this .stopped = true ;
695
- this .deferredCloseExecutor .shutdownNow ();
708
+ if (this .deferredCloseExecutor != null ) {
709
+ this .deferredCloseExecutor .shutdownNow ();
710
+ }
696
711
}
697
712
}
698
713
@@ -820,12 +835,12 @@ public Properties getCacheProperties() {
820
835
props .setProperty ("connectionCacheSize" , Integer .toString (this .connectionCacheSize ));
821
836
props .setProperty ("openConnections" , Integer .toString (countOpenConnections ()));
822
837
props .setProperty ("idleConnections" , Integer .toString (this .idleConnections .size ()));
823
- props .setProperty ("idleConnectionsHighWater" , Integer .toString (this .connectionHighWaterMark .get ()));
838
+ props .setProperty ("idleConnectionsHighWater" , Integer .toString (this .connectionHighWaterMark .get ()));
824
839
for (ChannelCachingConnectionProxy proxy : this .allocatedConnections ) {
825
840
putConnectionName (props , proxy , ":" + proxy .getLocalPort ());
826
841
}
827
842
for (Entry <ChannelCachingConnectionProxy , LinkedList <ChannelProxy >> entry :
828
- this .allocatedConnectionTransactionalChannels .entrySet ()) {
843
+ this .allocatedConnectionTransactionalChannels .entrySet ()) {
829
844
int port = entry .getKey ().getLocalPort ();
830
845
if (port > 0 && entry .getKey ().isOpen ()) {
831
846
LinkedList <ChannelProxy > channelList = entry .getValue ();
@@ -835,7 +850,7 @@ public Properties getCacheProperties() {
835
850
}
836
851
}
837
852
for (Entry <ChannelCachingConnectionProxy , LinkedList <ChannelProxy >> entry :
838
- this .allocatedConnectionNonTransactionalChannels .entrySet ()) {
853
+ this .allocatedConnectionNonTransactionalChannels .entrySet ()) {
839
854
int port = entry .getKey ().getLocalPort ();
840
855
if (port > 0 && entry .getKey ().isOpen ()) {
841
856
LinkedList <ChannelProxy > channelList = entry .getValue ();
@@ -880,6 +895,28 @@ private int countOpenConnections() {
880
895
return n ;
881
896
}
882
897
898
+ /**
899
+ * Determine the executor service used to close connections.
900
+ * @return specified executor service otherwise the default one is created and returned.
901
+ * @since 1.7.9
902
+ */
903
+ protected ExecutorService getDeferredCloseExecutor () {
904
+ if (getExecutorService () != null ) {
905
+ return getExecutorService ();
906
+ }
907
+ synchronized (this .connectionMonitor ) {
908
+ if (this .deferredCloseExecutor == null ) {
909
+ final String threadPrefix =
910
+ getBeanName () == null
911
+ ? DEFAULT_DEFERRED_POOL_PREFIX + threadPoolId .incrementAndGet ()
912
+ : getBeanName ();
913
+ ThreadFactory threadPoolFactory = new CustomizableThreadFactory (threadPrefix );
914
+ this .deferredCloseExecutor = Executors .newCachedThreadPool (threadPoolFactory );
915
+ }
916
+ }
917
+ return this .deferredCloseExecutor ;
918
+ }
919
+
883
920
@ Override
884
921
public String toString () {
885
922
return "CachingConnectionFactory [channelCacheSize=" + this .channelCacheSize + ", host=" + getHost ()
@@ -1033,7 +1070,7 @@ private void releasePermitIfNecessary(Object proxy) {
1033
1070
checkoutPermits .release ();
1034
1071
if (logger .isDebugEnabled ()) {
1035
1072
logger .debug ("Released permit for '" + this .theConnection + "', remaining: "
1036
- + checkoutPermits .availablePermits ());
1073
+ + checkoutPermits .availablePermits ());
1037
1074
}
1038
1075
}
1039
1076
else {
@@ -1097,9 +1134,7 @@ private void physicalClose() throws Exception {
1097
1134
if (CachingConnectionFactory .this .active &&
1098
1135
(CachingConnectionFactory .this .publisherConfirms ||
1099
1136
CachingConnectionFactory .this .publisherReturns )) {
1100
- ExecutorService executorService = (getExecutorService () != null
1101
- ? getExecutorService ()
1102
- : CachingConnectionFactory .this .deferredCloseExecutor );
1137
+ ExecutorService executorService = getDeferredCloseExecutor ();
1103
1138
final Channel channel = CachedChannelInvocationHandler .this .target ;
1104
1139
executorService .execute (new Runnable () {
1105
1140
@@ -1116,14 +1151,18 @@ public void run() {
1116
1151
catch (InterruptedException e ) {
1117
1152
Thread .currentThread ().interrupt ();
1118
1153
}
1119
- catch (Exception e ) { }
1154
+ catch (Exception e ) {
1155
+ }
1120
1156
finally {
1121
1157
try {
1122
1158
channel .close ();
1123
1159
}
1124
- catch (IOException e ) { }
1125
- catch (AlreadyClosedException e ) { }
1126
- catch (TimeoutException e ) { }
1160
+ catch (IOException e ) {
1161
+ }
1162
+ catch (AlreadyClosedException e ) {
1163
+ }
1164
+ catch (TimeoutException e ) {
1165
+ }
1127
1166
catch (ShutdownSignalException e ) {
1128
1167
if (!RabbitUtils .isNormalShutdown (e )) {
1129
1168
logger .debug ("Unexpected exception on deferred close" , e );
@@ -1253,8 +1292,8 @@ public int getLocalPort() {
1253
1292
@ Override
1254
1293
public String toString () {
1255
1294
return "Proxy@" + ObjectUtils .getIdentityHexString (this ) + " "
1256
- + (CachingConnectionFactory .this .cacheMode == CacheMode .CHANNEL ? "Shared " : "Dedicated " )
1257
- + "Rabbit Connection: " + this .target ;
1295
+ + (CachingConnectionFactory .this .cacheMode == CacheMode .CHANNEL ? "Shared " : "Dedicated " )
1296
+ + "Rabbit Connection: " + this .target ;
1258
1297
}
1259
1298
1260
1299
}
0 commit comments