@Override public void bindRequestor( String name, MessageChannel requests, MessageChannel replies, Properties properties) { if (logger.isInfoEnabled()) { logger.info("binding requestor: " + name); } validateProducerProperties(name, properties, SUPPORTED_REQUESTING_PRODUCER_PROPERTIES); Assert.isInstanceOf(SubscribableChannel.class, requests); RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties); String queueName = applyRequests(name); AmqpOutboundEndpoint queue = this.buildOutboundEndpoint(queueName, accessor, this.rabbitTemplate); queue.setBeanFactory(this.getBeanFactory()); String replyQueueName = accessor.getPrefix(this.defaultPrefix) + name + ".replies." + this.getIdGenerator().generateId(); this.doRegisterProducer(name, requests, queue, replyQueueName, accessor); Queue replyQueue = new Queue(replyQueueName, false, false, true); // auto-delete declareQueueIfNotPresent(replyQueue); // register with context so it will be redeclared after a connection failure if (!this.autoDeclareContext.containsBean(replyQueueName)) { this.autoDeclareContext.getBeanFactory().registerSingleton(replyQueueName, replyQueue); } this.doRegisterConsumer(name, replies, replyQueue, accessor, false); }
private RabbitTemplate determineRabbitTemplate(RabbitPropertiesAccessor properties) { RabbitTemplate rabbitTemplate = null; if (properties.isBatchingEnabled(this.defaultBatchingEnabled)) { BatchingStrategy batchingStrategy = new SimpleBatchingStrategy( properties.getBatchSize(this.defaultBatchSize), properties.geteBatchBufferLimit(this.defaultBatchBufferLimit), properties.getBatchTimeout(this.defaultBatchTimeout)); rabbitTemplate = new BatchingRabbitTemplate( batchingStrategy, getApplicationContext() .getBean(IntegrationContextUtils.TASK_SCHEDULER_BEAN_NAME, TaskScheduler.class)); rabbitTemplate.setConnectionFactory(this.connectionFactory); } if (properties.isCompress(this.defaultCompress)) { if (rabbitTemplate == null) { rabbitTemplate = new RabbitTemplate(this.connectionFactory); } rabbitTemplate.setBeforePublishPostProcessors(this.compressingPostProcessor); rabbitTemplate.afterPropertiesSet(); } if (rabbitTemplate == null) { rabbitTemplate = this.rabbitTemplate; } return rabbitTemplate; }
private Map<String, Object> queueArgs(RabbitPropertiesAccessor accessor, String queueName) { Map<String, Object> args = new HashMap<>(); if (accessor.getAutoBindDLQ(this.defaultAutoBindDLQ)) { args.put( "x-dead-letter-exchange", applyPrefix(accessor.getPrefix(this.defaultPrefix), "DLX")); args.put("x-dead-letter-routing-key", queueName); } return args; }
private void configureOutboundHandler( AmqpOutboundEndpoint handler, RabbitPropertiesAccessor properties) { DefaultAmqpHeaderMapper mapper = new DefaultAmqpHeaderMapper(); mapper.setRequestHeaderNames( properties.getRequestHeaderPattens(this.defaultRequestHeaderPatterns)); mapper.setReplyHeaderNames(properties.getReplyHeaderPattens(this.defaultReplyHeaderPatterns)); handler.setHeaderMapper(mapper); handler.setDefaultDeliveryMode(properties.getDeliveryMode(this.defaultDefaultDeliveryMode)); handler.setBeanFactory(this.getBeanFactory()); handler.afterPropertiesSet(); }
@Override public void bindPubSubProducer( String name, MessageChannel moduleOutputChannel, Properties properties) { validateProducerProperties(name, properties, SUPPORTED_PUBSUB_PRODUCER_PROPERTIES); RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties); String exchangeName = applyPrefix(accessor.getPrefix(this.defaultPrefix), applyPubSub(name)); declareExchangeIfNotPresent(new FanoutExchange(exchangeName)); AmqpOutboundEndpoint fanout = new AmqpOutboundEndpoint(determineRabbitTemplate(accessor)); fanout.setExchangeName(exchangeName); configureOutboundHandler(fanout, accessor); doRegisterProducer(name, moduleOutputChannel, fanout, accessor); }
private MessageRecoverer determineRecoverer(String name, RabbitPropertiesAccessor properties) { if (properties.getRepublishToDLQ(this.defaultRepublishToDLQ)) { RabbitTemplate errorTemplate = new RabbitTemplate(this.connectionFactory); String prefix = properties.getPrefix(this.defaultPrefix); RepublishMessageRecoverer republishMessageRecoverer = new RepublishMessageRecoverer( errorTemplate, deadLetterExchangeName(prefix), applyPrefix(prefix, name)); // TODO: Add container id to republished message headers? (Needs AMQP-489). return republishMessageRecoverer; } else { return new RejectAndDontRequeueRecoverer(); } }
private SendingHandler( MessageHandler delegate, String replyTo, RabbitPropertiesAccessor properties) { this.delegate = delegate; this.replyTo = replyTo; this.partitioningMetadata = new PartitioningMetadata(properties, properties.getNextModuleCount()); this.setBeanFactory(RabbitMessageChannelBinder.this.getBeanFactory()); }
/** * If so requested, declare the DLX/DLQ and bind it. The DLQ is bound to the DLX with a routing * key of the original queue name because we use default exchange routing by queue name for the * original message. * * @param name The name. * @param properties The properties accessor. */ private void autoBindDLQ(final String name, RabbitPropertiesAccessor properties) { if (logger.isDebugEnabled()) { logger.debug( "autoBindDLQ=" + properties.getAutoBindDLQ(this.defaultAutoBindDLQ) + " for: " + name); } if (properties.getAutoBindDLQ(this.defaultAutoBindDLQ)) { String prefix = properties.getPrefix(this.defaultPrefix); String queueName = applyPrefix(prefix, name); String dlqName = constructDLQName(queueName); Queue dlq = new Queue(dlqName); declareQueueIfNotPresent(dlq); final String dlxName = deadLetterExchangeName(prefix); final DirectExchange dlx = new DirectExchange(dlxName); declareExchangeIfNotPresent(dlx); this.rabbitAdmin.declareBinding(BindingBuilder.bind(dlq).to(dlx).with(queueName)); } }
@Override public void bindReplier( String name, MessageChannel requests, MessageChannel replies, Properties properties) { if (logger.isInfoEnabled()) { logger.info("binding replier: " + name); } validateConsumerProperties(name, properties, SUPPORTED_REPLYING_CONSUMER_PROPERTIES); RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties); Queue requestQueue = new Queue(applyPrefix(accessor.getPrefix(this.defaultPrefix), applyRequests(name))); declareQueueIfNotPresent(requestQueue); this.doRegisterConsumer(name, requests, requestQueue, accessor, false); AmqpOutboundEndpoint replyQueue = new AmqpOutboundEndpoint(rabbitTemplate); replyQueue.setExpressionRoutingKey( EXPRESSION_PARSER.parseExpression("headers['" + AmqpHeaders.REPLY_TO + "']")); configureOutboundHandler(replyQueue, accessor); doRegisterProducer(name, replies, replyQueue, accessor); }
private AmqpOutboundEndpoint buildOutboundEndpoint( final String name, RabbitPropertiesAccessor properties, RabbitTemplate rabbitTemplate) { String queueName = applyPrefix(properties.getPrefix(this.defaultPrefix), name); String partitionKeyExtractorClass = properties.getPartitionKeyExtractorClass(); Expression partitionKeyExpression = properties.getPartitionKeyExpression(); AmqpOutboundEndpoint queue = new AmqpOutboundEndpoint(rabbitTemplate); if (partitionKeyExpression == null && !StringUtils.hasText(partitionKeyExtractorClass)) { declareQueueIfNotPresent(new Queue(queueName)); queue.setRoutingKey(queueName); // uses default exchange } else { queue.setExpressionRoutingKey( EXPRESSION_PARSER.parseExpression(buildPartitionRoutingExpression(queueName))); // if the stream is partitioned, create one queue for each target partition for (int i = 0; i < properties.getNextModuleCount(); i++) { this.rabbitAdmin.declareQueue(new Queue(queueName + "-" + i)); } } configureOutboundHandler(queue, properties); return queue; }
@Override public void bindPubSubConsumer( String name, MessageChannel moduleInputChannel, Properties properties) { String exchangeName = BinderUtils.removeGroupFromPubSub(name); if (logger.isInfoEnabled()) { logger.info("declaring pubsub for inbound: " + name + ", bound to: " + exchangeName); } RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties); validateConsumerProperties(name, properties, SUPPORTED_PUBSUB_CONSUMER_PROPERTIES); String prefix = accessor.getPrefix(this.defaultPrefix); FanoutExchange exchange = new FanoutExchange(applyPrefix(prefix, applyPubSub(exchangeName))); declareExchangeIfNotPresent(exchange); Queue queue; boolean durable = accessor.isDurable(this.defaultDurableSubscription); String queueName = applyPrefix(prefix, name); if (durable) { Map<String, Object> args = queueArgs(accessor, queueName); queue = new Queue(queueName, true, false, false, args); } else { queue = new Queue(queueName, false, false, true); } declareQueueIfNotPresent(queue); org.springframework.amqp.core.Binding binding = BindingBuilder.bind(queue).to(exchange); this.rabbitAdmin.declareBinding(binding); // register with context so they will be redeclared after a connection failure if (!this.autoDeclareContext.containsBean(applyPubSub(name))) { this.autoDeclareContext.getBeanFactory().registerSingleton(applyPubSub(name), queue); } String bindingBeanName = exchange.getName() + "." + queue.getName() + ".binding"; if (!this.autoDeclareContext.containsBean(bindingBeanName)) { this.autoDeclareContext.getBeanFactory().registerSingleton(bindingBeanName, binding); } doRegisterConsumer(name, moduleInputChannel, queue, accessor, true); if (durable) { autoBindDLQ(name, accessor); } }
@Override public void bindConsumer( final String name, MessageChannel moduleInputChannel, Properties properties) { if (logger.isInfoEnabled()) { logger.info("declaring queue for inbound: " + name); } if (name.startsWith(P2P_NAMED_CHANNEL_TYPE_PREFIX)) { validateConsumerProperties(name, properties, SUPPORTED_NAMED_CONSUMER_PROPERTIES); } else { validateConsumerProperties(name, properties, SUPPORTED_CONSUMER_PROPERTIES); } RabbitPropertiesAccessor accessor = new RabbitPropertiesAccessor(properties); String queueName = applyPrefix(accessor.getPrefix(this.defaultPrefix), name); int partitionIndex = accessor.getPartitionIndex(); if (partitionIndex >= 0) { queueName += "-" + partitionIndex; } Map<String, Object> args = queueArgs(accessor, queueName); Queue queue = new Queue(queueName, true, false, false, args); declareQueueIfNotPresent(queue); autoBindDLQ(name, accessor); doRegisterConsumer(name, moduleInputChannel, queue, accessor, false); bindExistingProducerDirectlyIfPossible(name, moduleInputChannel); }
private void doRegisterConsumer( String name, MessageChannel moduleInputChannel, Queue queue, RabbitPropertiesAccessor properties, boolean isPubSub) { // Fix for XD-2503 // Temporarily overrides the thread context classloader with the one where the // SimpleMessageListenerContainer // is defined // This allows for the proxying that happens while initializing the // SimpleMessageListenerContainer to work // correctly ClassLoader originalClassloader = Thread.currentThread().getContextClassLoader(); try { ClassUtils.overrideThreadContextClassLoader( SimpleMessageListenerContainer.class.getClassLoader()); SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer(this.connectionFactory); listenerContainer.setAcknowledgeMode( properties.getAcknowledgeMode(this.defaultAcknowledgeMode)); listenerContainer.setChannelTransacted( properties.getTransacted(this.defaultChannelTransacted)); listenerContainer.setDefaultRequeueRejected( properties.getRequeueRejected(this.defaultDefaultRequeueRejected)); if (!isPubSub) { int concurrency = properties.getConcurrency(this.defaultConcurrency); concurrency = concurrency > 0 ? concurrency : 1; listenerContainer.setConcurrentConsumers(concurrency); int maxConcurrency = properties.getMaxConcurrency(this.defaultMaxConcurrency); if (maxConcurrency > concurrency) { listenerContainer.setMaxConcurrentConsumers(maxConcurrency); } } listenerContainer.setPrefetchCount(properties.getPrefetchCount(this.defaultPrefetchCount)); listenerContainer.setTxSize(properties.getTxSize(this.defaultTxSize)); listenerContainer.setTaskExecutor(new SimpleAsyncTaskExecutor(queue.getName() + "-")); listenerContainer.setQueues(queue); int maxAttempts = properties.getMaxAttempts(this.defaultMaxAttempts); if (maxAttempts > 1 || properties.getRepublishToDLQ(this.defaultRepublishToDLQ)) { RetryOperationsInterceptor retryInterceptor = RetryInterceptorBuilder.stateless() .maxAttempts(maxAttempts) .backOffOptions( properties.getBackOffInitialInterval(this.defaultBackOffInitialInterval), properties.getBackOffMultiplier(this.defaultBackOffMultiplier), properties.getBackOffMaxInterval(this.defaultBackOffMaxInterval)) .recoverer(determineRecoverer(name, properties)) .build(); listenerContainer.setAdviceChain(new Advice[] {retryInterceptor}); } listenerContainer.setAfterReceivePostProcessors(this.decompressingPostProcessor); listenerContainer.setMessagePropertiesConverter( RabbitMessageChannelBinder.inboundMessagePropertiesConverter); listenerContainer.afterPropertiesSet(); AmqpInboundChannelAdapter adapter = new AmqpInboundChannelAdapter(listenerContainer); adapter.setBeanFactory(this.getBeanFactory()); DirectChannel bridgeToModuleChannel = new DirectChannel(); bridgeToModuleChannel.setBeanFactory(this.getBeanFactory()); bridgeToModuleChannel.setBeanName(name + ".bridge"); adapter.setOutputChannel(bridgeToModuleChannel); adapter.setBeanName("inbound." + name); DefaultAmqpHeaderMapper mapper = new DefaultAmqpHeaderMapper(); mapper.setRequestHeaderNames( properties.getRequestHeaderPattens(this.defaultRequestHeaderPatterns)); mapper.setReplyHeaderNames(properties.getReplyHeaderPattens(this.defaultReplyHeaderPatterns)); adapter.setHeaderMapper(mapper); adapter.afterPropertiesSet(); Binding consumerBinding = Binding.forConsumer(name, adapter, moduleInputChannel, properties); addBinding(consumerBinding); ReceivingHandler convertingBridge = new ReceivingHandler(); convertingBridge.setOutputChannel(moduleInputChannel); convertingBridge.setBeanName(name + ".convert.bridge"); convertingBridge.afterPropertiesSet(); bridgeToModuleChannel.subscribe(convertingBridge); consumerBinding.start(); } finally { Thread.currentThread().setContextClassLoader(originalClassloader); } }