|
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;
|
|
52 | 53 | import org.springframework.beans.factory.InitializingBean;
|
53 | 54 | import org.springframework.jmx.export.annotation.ManagedAttribute;
|
54 | 55 | import org.springframework.jmx.export.annotation.ManagedResource;
|
| 56 | +import org.springframework.scheduling.concurrent.CustomizableThreadFactory; |
55 | 57 | import org.springframework.util.Assert;
|
56 | 58 | import org.springframework.util.ObjectUtils;
|
57 | 59 | import org.springframework.util.StringUtils;
|
|
89 | 91 | * @author Gary Russell
|
90 | 92 | * @author Artem Bilan
|
91 | 93 | * @author Steve Powell
|
| 94 | + * @author Will Droste |
92 | 95 | */
|
93 | 96 | @ManagedResource
|
94 | 97 | public class CachingConnectionFactory extends AbstractConnectionFactory
|
95 | 98 | implements InitializingBean, ShutdownListener, PublisherCallbackChannelConnectionFactory {
|
96 | 99 |
|
97 | 100 | private static final int DEFAULT_CHANNEL_CACHE_SIZE = 25;
|
98 | 101 |
|
| 102 | + private static final String DEFAULT_DEFERRED_POOL_PREFIX = "spring-rabbit-deferred-pool-"; |
| 103 | + |
| 104 | + /** |
| 105 | + * Create a unique ID for the pool. |
| 106 | + */ |
| 107 | + private static final AtomicInteger threadPoolId = new AtomicInteger(); |
| 108 | + |
99 | 109 | private static final Set<String> txStarts = new HashSet<>(Arrays.asList("basicPublish", "basicAck",
|
100 | 110 | "basicNack", "basicReject"));
|
101 | 111 |
|
@@ -169,6 +179,10 @@ public enum CacheMode {
|
169 | 179 |
|
170 | 180 | /** Executor used for deferred close if no explicit executor set. */
|
171 | 181 | private final ExecutorService deferredCloseExecutor = Executors.newCachedThreadPool();
|
| 182 | + /** |
| 183 | + * Executor used for deferred close if no explicit executor set. |
| 184 | + */ |
| 185 | + private ExecutorService deferredCloseExecutor; |
172 | 186 |
|
173 | 187 |
|
174 | 188 | /**
|
@@ -734,7 +748,9 @@ public final void destroy() {
|
734 | 748 | resetConnection();
|
735 | 749 | if (getContextStopped()) {
|
736 | 750 | this.stopped = true;
|
737 |
| - this.deferredCloseExecutor.shutdownNow(); |
| 751 | + if (this.deferredCloseExecutor != null) { |
| 752 | + this.deferredCloseExecutor.shutdownNow(); |
| 753 | + } |
738 | 754 | }
|
739 | 755 | }
|
740 | 756 |
|
@@ -878,6 +894,28 @@ private int countOpenConnections() {
|
878 | 894 | return n;
|
879 | 895 | }
|
880 | 896 |
|
| 897 | + /** |
| 898 | + * Determine the executor service used to close connections. |
| 899 | + * @return specified executor service otherwise the default one is created and returned. |
| 900 | + * @since 1.7.9 |
| 901 | + */ |
| 902 | + protected ExecutorService getDeferredCloseExecutor() { |
| 903 | + if (getExecutorService() != null) { |
| 904 | + return getExecutorService(); |
| 905 | + } |
| 906 | + synchronized (this.connectionMonitor) { |
| 907 | + if (this.deferredCloseExecutor == null) { |
| 908 | + final String threadPrefix = |
| 909 | + getBeanName() == null |
| 910 | + ? DEFAULT_DEFERRED_POOL_PREFIX + threadPoolId.incrementAndGet() |
| 911 | + : getBeanName(); |
| 912 | + ThreadFactory threadPoolFactory = new CustomizableThreadFactory(threadPrefix); |
| 913 | + this.deferredCloseExecutor = Executors.newCachedThreadPool(threadPoolFactory); |
| 914 | + } |
| 915 | + } |
| 916 | + return this.deferredCloseExecutor; |
| 917 | + } |
| 918 | + |
881 | 919 | @Override
|
882 | 920 | public String toString() {
|
883 | 921 | return "CachingConnectionFactory [channelCacheSize=" + this.channelCacheSize + ", host=" + getHost()
|
@@ -1119,9 +1157,7 @@ private void physicalClose() throws Exception {
|
1119 | 1157 | }
|
1120 | 1158 |
|
1121 | 1159 | private void asyncClose() {
|
1122 |
| - ExecutorService executorService = (getExecutorService() != null |
1123 |
| - ? getExecutorService() |
1124 |
| - : CachingConnectionFactory.this.deferredCloseExecutor); |
| 1160 | + ExecutorService executorService = getDeferredCloseExecutor(); |
1125 | 1161 | final Channel channel = CachedChannelInvocationHandler.this.target;
|
1126 | 1162 | executorService.execute(() -> {
|
1127 | 1163 | try {
|
|
0 commit comments