0
# Destination Resolution
1
2
Pluggable destination resolution supporting JNDI lookups, dynamic destination creation, bean factory integration, and caching for flexible destination management. Spring JMS provides multiple strategies for resolving JMS destinations to accommodate various deployment environments and naming conventions.
3
4
## Capabilities
5
6
### DestinationResolver Interface
7
8
Core strategy interface for resolving destination names to JMS Destination objects, enabling pluggable destination resolution strategies.
9
10
```java { .api }
11
/**
12
* Strategy interface for resolving JMS destination names to Destination objects
13
*/
14
public interface DestinationResolver {
15
16
/**
17
* Resolve the given destination name to a JMS Destination
18
* @param session the current JMS session
19
* @param destinationName the name of the destination to resolve
20
* @param pubSubDomain whether the domain is pub-sub (topic) or point-to-point (queue)
21
* @return the resolved Destination object
22
* @throws JMSException in case of JMS errors
23
* @throws DestinationResolutionException in case of resolution errors
24
*/
25
Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
26
throws JMSException;
27
}
28
```
29
30
### DynamicDestinationResolver
31
32
Default destination resolver that creates destinations dynamically using JMS Session methods, suitable for JMS providers that support dynamic destination creation.
33
34
```java { .api }
35
/**
36
* Default destination resolver that creates destinations dynamically
37
*/
38
public class DynamicDestinationResolver implements DestinationResolver {
39
40
public DynamicDestinationResolver();
41
42
/**
43
* Resolve destination name by creating queue or topic dynamically
44
* @param session the JMS session
45
* @param destinationName the destination name
46
* @param pubSubDomain true for topics, false for queues
47
* @return the resolved destination
48
* @throws JMSException in case of JMS errors
49
*/
50
@Override
51
public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
52
throws JMSException;
53
54
// Template methods for creating destinations
55
protected Queue resolveQueueName(Session session, String queueName) throws JMSException;
56
protected Topic resolveTopicName(Session session, String topicName) throws JMSException;
57
}
58
```
59
60
### JndiDestinationResolver
61
62
JNDI-based destination resolver that looks up destinations from a JNDI directory, commonly used in Java EE application servers.
63
64
```java { .api }
65
/**
66
* Destination resolver that uses JNDI lookups
67
*/
68
public class JndiDestinationResolver extends JndiLocatorSupport implements DestinationResolver {
69
70
// Constructors
71
public JndiDestinationResolver();
72
73
// JNDI configuration
74
public void setJndiTemplate(JndiTemplate jndiTemplate);
75
public void setJndiEnvironment(Properties jndiEnvironment);
76
public void setResourceRef(boolean resourceRef);
77
78
// Caching configuration
79
public void setCache(boolean cache);
80
public boolean isCache();
81
public void clearCache();
82
83
// Fallback configuration
84
public void setFallbackToDynamicDestination(boolean fallbackToDynamicDestination);
85
public boolean isFallbackToDynamicDestination();
86
87
// Lookup methods
88
protected Destination lookupDestination(String destinationName) throws NamingException;
89
protected Queue lookupQueue(String queueName) throws NamingException;
90
protected Topic lookupTopic(String topicName) throws NamingException;
91
92
// Resolution method
93
@Override
94
public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
95
throws JMSException;
96
}
97
```
98
99
### BeanFactoryDestinationResolver
100
101
Destination resolver that resolves destinations as Spring-managed beans from the application context, providing integration with Spring's dependency injection.
102
103
```java { .api }
104
/**
105
* Destination resolver that resolves destinations as Spring beans
106
*/
107
public class BeanFactoryDestinationResolver implements DestinationResolver, BeanFactoryAware {
108
109
public BeanFactoryDestinationResolver();
110
public BeanFactoryDestinationResolver(BeanFactory beanFactory);
111
112
// Bean factory configuration
113
public void setBeanFactory(BeanFactory beanFactory);
114
protected BeanFactory getBeanFactory();
115
116
// Resolution method
117
@Override
118
public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
119
throws JMSException;
120
121
// Template method for bean lookup
122
protected Destination resolveDestinationName(String destinationName);
123
}
124
```
125
126
### CachingDestinationResolver
127
128
Decorator for destination resolvers that caches resolved destinations for improved performance by avoiding repeated resolution calls.
129
130
```java { .api }
131
/**
132
* Caching wrapper for destination resolvers
133
*/
134
public class CachingDestinationResolver implements DestinationResolver {
135
136
// Constructors
137
public CachingDestinationResolver();
138
public CachingDestinationResolver(DestinationResolver targetResolver);
139
140
// Target resolver configuration
141
public void setTargetResolver(DestinationResolver targetResolver);
142
public DestinationResolver getTargetResolver();
143
144
// Cache management
145
public void clearCache();
146
public int getCacheSize();
147
148
// Resolution method with caching
149
@Override
150
public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
151
throws JMSException;
152
}
153
```
154
155
### JmsDestinationAccessor
156
157
Abstract base class for JMS accessor objects that use destination resolvers, providing common configuration for destination resolution and pub/sub domain handling.
158
159
```java { .api }
160
/**
161
* Base class for JMS accessor objects with destination resolution support
162
*/
163
public abstract class JmsDestinationAccessor extends JmsAccessor {
164
165
// Destination resolver configuration
166
public void setDestinationResolver(DestinationResolver destinationResolver);
167
public DestinationResolver getDestinationResolver();
168
169
// Pub/Sub domain configuration
170
public void setPubSubDomain(boolean pubSubDomain);
171
public boolean isPubSubDomain();
172
173
// Destination resolution methods
174
protected Destination resolveDestinationName(Session session, String destinationName) throws JMSException;
175
protected Queue resolveQueueName(Session session, String queueName) throws JMSException;
176
protected Topic resolveTopicName(Session session, String topicName) throws JMSException;
177
}
178
```
179
180
### Destination Resolution Exceptions
181
182
Exception hierarchy for destination resolution errors with specific error categorization.
183
184
```java { .api }
185
/**
186
* Exception thrown when destination resolution fails
187
*/
188
public class DestinationResolutionException extends JmsException {
189
190
public DestinationResolutionException(String msg);
191
public DestinationResolutionException(String msg, Throwable cause);
192
}
193
```
194
195
**Usage Examples:**
196
197
```java
198
import org.springframework.jms.support.destination.*;
199
import javax.naming.Context;
200
import java.util.Properties;
201
202
// Configuration for different destination resolution strategies
203
@Configuration
204
public class DestinationConfig {
205
206
// Dynamic destination resolver (default)
207
@Bean
208
public DestinationResolver dynamicDestinationResolver() {
209
return new DynamicDestinationResolver();
210
}
211
212
// JNDI destination resolver for Java EE environments
213
@Bean
214
public DestinationResolver jndiDestinationResolver() {
215
JndiDestinationResolver resolver = new JndiDestinationResolver();
216
resolver.setResourceRef(true); // Use java:comp/env/ prefix
217
resolver.setCache(true); // Enable caching for performance
218
resolver.setFallbackToDynamicDestination(true); // Fallback if JNDI lookup fails
219
220
// Configure JNDI environment
221
Properties jndiProps = new Properties();
222
jndiProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.activemq.jndi.ActiveMQInitialContextFactory");
223
jndiProps.setProperty(Context.PROVIDER_URL, "tcp://localhost:61616");
224
resolver.setJndiEnvironment(jndiProps);
225
226
return resolver;
227
}
228
229
// Bean factory destination resolver
230
@Bean
231
public DestinationResolver beanFactoryDestinationResolver() {
232
return new BeanFactoryDestinationResolver();
233
}
234
235
// Caching destination resolver wrapper
236
@Bean
237
public DestinationResolver cachingDestinationResolver() {
238
return new CachingDestinationResolver(jndiDestinationResolver());
239
}
240
241
// Define destinations as Spring beans
242
@Bean
243
public Queue orderQueue() {
244
return new ActiveMQQueue("order.queue");
245
}
246
247
@Bean
248
public Topic notificationTopic() {
249
return new ActiveMQTopic("notification.topic");
250
}
251
252
// JmsTemplate with custom destination resolver
253
@Bean
254
public JmsTemplate jmsTemplate() {
255
JmsTemplate template = new JmsTemplate(connectionFactory());
256
template.setDestinationResolver(cachingDestinationResolver());
257
return template;
258
}
259
260
// Message listener container with destination resolver
261
@Bean
262
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
263
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
264
factory.setConnectionFactory(connectionFactory());
265
factory.setDestinationResolver(cachingDestinationResolver());
266
return factory;
267
}
268
}
269
270
// Service using destination resolution
271
@Service
272
public class MessagingService {
273
274
@Autowired
275
private JmsTemplate jmsTemplate;
276
277
@Autowired
278
private DestinationResolver destinationResolver;
279
280
// Using destination names (resolved automatically by JmsTemplate)
281
public void sendToQueue(String queueName, Object message) {
282
jmsTemplate.convertAndSend(queueName, message);
283
}
284
285
public void sendToTopic(String topicName, Object message) {
286
jmsTemplate.setPubSubDomain(true);
287
jmsTemplate.convertAndSend(topicName, message);
288
}
289
290
// Manual destination resolution
291
public void sendWithManualResolution(String destinationName, Object message) {
292
jmsTemplate.send(session -> {
293
// Manually resolve destination
294
Destination destination = destinationResolver.resolveDestinationName(
295
session, destinationName, false); // false = queue, true = topic
296
297
MessageProducer producer = session.createProducer(destination);
298
ObjectMessage objMessage = session.createObjectMessage((Serializable) message);
299
producer.send(objMessage);
300
301
return objMessage;
302
});
303
}
304
}
305
306
// Custom destination resolver implementation
307
@Component
308
public class CustomDestinationResolver implements DestinationResolver {
309
310
private final Map<String, String> destinationMappings = new HashMap<>();
311
private final DestinationResolver fallbackResolver = new DynamicDestinationResolver();
312
313
@PostConstruct
314
public void initializeMappings() {
315
// Map logical names to physical destinations
316
destinationMappings.put("orders", "app.orders.v1");
317
destinationMappings.put("notifications", "app.notifications.v1");
318
destinationMappings.put("audit", "app.audit.v1");
319
}
320
321
@Override
322
public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
323
throws JMSException {
324
325
// Apply destination mapping
326
String physicalName = destinationMappings.getOrDefault(destinationName, destinationName);
327
328
// Add environment prefix
329
String environment = System.getProperty("app.environment", "dev");
330
String resolvedName = environment + "." + physicalName;
331
332
// Use fallback resolver for actual destination creation
333
return fallbackResolver.resolveDestinationName(session, resolvedName, pubSubDomain);
334
}
335
}
336
337
// Destination resolver with conditional logic
338
@Component
339
@Profile("production")
340
public class ProductionDestinationResolver implements DestinationResolver {
341
342
@Autowired
343
private JndiDestinationResolver jndiResolver;
344
345
@Autowired
346
private DynamicDestinationResolver dynamicResolver;
347
348
@Override
349
public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
350
throws JMSException {
351
352
// Try JNDI first for production destinations
353
try {
354
return jndiResolver.resolveDestinationName(session, destinationName, pubSubDomain);
355
} catch (DestinationResolutionException e) {
356
// Fallback to dynamic resolution for temporary destinations
357
if (destinationName.startsWith("temp.") || destinationName.startsWith("reply.")) {
358
return dynamicResolver.resolveDestinationName(session, destinationName, pubSubDomain);
359
}
360
throw e;
361
}
362
}
363
}
364
```