You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2021/02/24 16:37:16 UTC

[camel] 01/02: CAMEL-16222: camel-core - ExchangeFactory SPI to allow to use exchange pooling

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch exchange-factory2
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 4554dba59f9d18dfdcc9f4bfb672655daa7b6dea
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Feb 24 17:15:34 2021 +0100

    CAMEL-16222: camel-core - ExchangeFactory SPI to allow to use exchange pooling
---
 .../src/main/java/__name__Consumer.java            |   3 +-
 camel-dependencies/pom.xml                         |   2 +-
 .../main/camel-main-configuration-metadata.json    |   2 +
 .../apache/camel/component/ahc/ws/WsConsumer.java  |   2 +-
 .../apache/camel/component/apns/ApnsConsumer.java  |   2 +-
 .../apache/camel/component/as2/AS2Consumer.java    |   9 +-
 .../camel/component/asterisk/AsteriskConsumer.java |   9 +-
 .../consumer/AtmosScheduledPollConsumer.java       |   4 -
 .../consumer/AtmosScheduledPollGetConsumer.java    |  14 +-
 .../atmosphere/websocket/WebsocketConsumer.java    |   6 +-
 .../atomix/client/map/AtomixMapConsumer.java       |   2 +-
 .../client/messaging/AtomixMessagingConsumer.java  |   2 +-
 .../atomix/client/queue/AtomixQueueConsumer.java   |   2 +-
 .../atomix/client/set/AtomixSetConsumer.java       |   2 +-
 .../atomix/client/value/AtomixValueConsumer.java   |   2 +-
 .../camel/attachment/DefaultAttachmentMessage.java |   5 +
 .../apache/camel/component/avro/AvroEndpoint.java  |  14 -
 .../apache/camel/component/avro/AvroListener.java  |  16 +-
 .../aws2/ddbstream/Ddb2StreamConsumer.java         |   8 +-
 .../aws2/ddbstream/Ddb2StreamEndpoint.java         |   9 -
 .../component/aws2/kinesis/Kinesis2Consumer.java   |  13 +-
 .../component/aws2/kinesis/Kinesis2Endpoint.java   |  11 -
 .../camel/component/aws2/s3/AWS2S3Consumer.java    |  75 ++-
 .../camel/component/aws2/s3/AWS2S3Endpoint.java    |  72 ---
 .../camel/component/aws2/sqs/Sqs2Consumer.java     |  52 +-
 .../camel/component/aws2/sqs/Sqs2Endpoint.java     |  44 --
 .../azure/eventhubs/EventHubsConsumer.java         |  34 +-
 .../azure/eventhubs/EventHubsEndpoint.java         |  32 -
 .../component/azure/storage/blob/BlobConsumer.java |   2 +-
 .../azure/storage/datalake/DataLakeConsumer.java   |   2 +-
 .../azure/storage/queue/QueueConsumer.java         |  13 +-
 .../azure/storage/queue/QueueEndpoint.java         |  13 -
 .../component/beanstalk/BeanstalkConsumer.java     |   3 +-
 .../component/cassandra/CassandraConsumer.java     |   7 +-
 .../apache/camel/component/cmis/CMISConsumer.java  |   2 +-
 .../org/apache/camel/coap/CamelCoapResource.java   |   3 +-
 .../camel/component/cometd/CometdConsumer.java     |  20 +-
 .../camel/component/cometd/CometdConsumerTest.java |  12 +
 .../consul/endpoint/ConsulEventConsumer.java       |  44 +-
 .../consul/endpoint/ConsulKeyValueConsumer.java    |  35 +-
 .../camel/component/corda/CordaConsumer.java       |  14 +-
 .../component/couchbase/CouchbaseConsumer.java     |  55 +-
 .../component/couchdb/CouchDbChangesetTracker.java |   7 +-
 .../camel/component/couchdb/CouchDbConsumer.java   |  19 +-
 .../camel/component/couchdb/CouchDbEndpoint.java   |  13 -
 .../couchdb/CouchDbChangesetTrackerTest.java       |  14 +-
 .../component/couchdb/CouchDbEndpointTest.java     |  27 -
 .../camel/component/dataset/DataSetConsumer.java   |  35 +-
 .../camel/component/dataset/DataSetEndpoint.java   |   4 +-
 .../camel/component/debezium/DebeziumConsumer.java |   3 +-
 .../camel/component/debezium/DebeziumEndpoint.java |   9 +-
 .../component/debezium/DebeziumEndpointTest.java   |  12 +-
 .../component/disruptor/DisruptorConsumer.java     |  11 +
 .../docker/consumer/DockerEventsConsumer.java      |  23 +-
 .../docker/consumer/DockerStatsConsumer.java       |  23 +-
 .../consumer/DropboxScheduledPollConsumer.java     |   4 -
 .../consumer/DropboxScheduledPollGetConsumer.java  |  45 +-
 .../DropboxScheduledPollSearchConsumer.java        |  33 +-
 .../camel/component/ehcache/EhcacheConsumer.java   |   4 +-
 .../elsql/ElSqlConsumerDynamicParameterTest.java   | 104 ----
 .../camel/component/etcd/EtcdStatsConsumer.java    |   2 +-
 .../camel/component/etcd/EtcdWatchConsumer.java    |   6 +-
 .../camel/component/facebook/FacebookConsumer.java |   6 +-
 .../component/file/watch/FileWatchConsumer.java    |   2 +-
 .../apache/camel/component/file/FileConsumer.java  |   9 +
 .../camel/component/file/GenericFileConsumer.java  |   8 +-
 .../camel/component/flatpack/FlatpackEndpoint.java |   4 +-
 .../component/file/remote/RemoteFileConsumer.java  |   9 +
 .../remote/RemoteFileIgnoreDoPollErrorTest.java    |   8 +
 .../component/git/consumer/GitBranchConsumer.java  |   2 +-
 .../component/git/consumer/GitCommitConsumer.java  |   2 +-
 .../component/git/consumer/GitTagConsumer.java     |   2 +-
 .../component/github/consumer/CommitConsumer.java  |   2 +-
 .../component/github/consumer/EventsConsumer.java  |   2 +-
 .../consumer/PullRequestCommentConsumer.java       |   2 +-
 .../github/consumer/PullRequestConsumer.java       |   2 +-
 .../component/github/consumer/TagConsumer.java     |   2 +-
 .../mail/stream/GoogleMailStreamConsumer.java      |  43 +-
 .../mail/stream/GoogleMailStreamEndpoint.java      |  42 --
 .../google/pubsub/GooglePubsubConsumer.java        |   8 +-
 .../pubsub/consumer/CamelMessageReceiver.java      |   9 +-
 .../sheets/stream/GoogleSheetsStreamConsumer.java  |  48 +-
 .../sheets/stream/GoogleSheetsStreamEndpoint.java  |  37 --
 .../google/storage/GoogleCloudStorageConsumer.java |  64 +-
 .../google/storage/GoogleCloudStorageEndpoint.java |  59 --
 .../apache/camel/component/gora/GoraConsumer.java  |  10 +-
 .../camel/component/gora/GoraConsumerTest.java     |  88 ---
 .../guava/eventbus/CamelEventHandler.java          |  18 +-
 .../guava/eventbus/FilteringCamelEventHandler.java |   5 +-
 .../guava/eventbus/GuavaEventBusConsumer.java      |   8 +-
 .../guava/eventbus/GuavaEventBusEndpoint.java      |   7 -
 .../instance/HazelcastInstanceConsumer.java        |   4 +-
 .../hazelcast/list/HazelcastListConsumer.java      |   6 -
 .../hazelcast/listener/CamelListener.java          |   4 +-
 .../hazelcast/map/HazelcastMapConsumer.java        |   6 -
 .../multimap/HazelcastMultimapConsumer.java        |   6 -
 .../hazelcast/queue/HazelcastQueueConsumer.java    |   4 +-
 .../HazelcastReplicatedmapConsumer.java            |   6 -
 .../hazelcast/seda/HazelcastSedaConsumer.java      |  32 +-
 .../hazelcast/set/HazelcastSetConsumer.java        |   6 -
 .../hazelcast/topic/HazelcastTopicConsumer.java    |   6 -
 .../camel/component/hbase/HBaseConsumer.java       |   5 +-
 .../apache/camel/component/hdfs/HdfsConsumer.java  |  44 +-
 .../org/apache/camel/http/common/CamelServlet.java |   4 +-
 .../apache/camel/component/http/HttpProducer.java  |  15 +-
 .../apache/camel/component/iec60870/Constants.java |   5 +
 .../component/iec60870/client/ClientConsumer.java  |  30 +-
 .../ignite/events/IgniteEventsConsumer.java        |   3 +-
 .../ignite/messaging/IgniteMessagingConsumer.java  |  11 +-
 .../component/infinispan/InfinispanConsumer.java   |  28 +-
 .../apache/camel/component/irc/IrcConsumer.java    |  90 ++-
 .../apache/camel/component/irc/IrcEndpoint.java    |  77 +--
 .../camel/component/irc/IrcConsumerTest.java       |  12 +
 .../camel/component/ironmq/IronMQConsumer.java     |  19 +-
 .../camel/component/ironmq/IronMQEndpoint.java     |  21 -
 .../apache/camel/component/jbpm/JBPMConsumer.java  |   7 +-
 .../jbpm/server/CamelKieServerExtensionTest.java   |  45 --
 .../camel/component/jcache/JCacheConsumer.java     |   7 +-
 .../jclouds/JcloudsBlobStoreConsumer.java          |   2 +-
 .../camel/component/jclouds/JcloudsConsumer.java   |  46 --
 .../camel/component/jcr/EndpointEventListener.java |  12 +-
 .../apache/camel/component/jcr/JcrConsumer.java    |   2 +-
 .../component/jetty/CamelContinuationServlet.java  |   4 +-
 .../jgroups/raft/CamelRoleChangeListener.java      |  17 +-
 .../jgroups/raft/JGroupsRaftConsumer.java          |   2 +-
 .../jgroups/raft/JGroupsRaftEndpoint.java          |   7 -
 .../component/jgroups/CamelJGroupsReceiver.java    |  19 +-
 .../camel/component/jgroups/JGroupsConsumer.java   |   2 +-
 .../jgroups/CamelJGroupsReceiverTest.java          |  58 --
 .../apache/camel/component/jira/JiraConstants.java |   2 +
 .../jira/consumer/NewCommentsConsumer.java         |   2 +-
 .../component/jira/consumer/NewIssuesConsumer.java |   2 +-
 .../jira/consumer/WatchUpdatesConsumer.java        |   9 +-
 .../jira/consumer/WatchUpdatesConsumerTest.java    |   5 +-
 .../component/jms/EndpointMessageListener.java     |  28 +-
 .../apache/camel/component/jms/JmsConsumer.java    |   2 +-
 .../org/apache/camel/component/jms/JmsMessage.java |   8 +
 .../jms/JmsInOnlyPooledExchangeTest.java}          |  42 +-
 .../apache/camel/component/jmx/JMXConsumer.java    |   4 +-
 .../apache/camel/component/jooq/JooqConsumer.java  |   2 +-
 .../apache/camel/component/jpa/JpaConsumer.java    |  25 +-
 .../component/jt400/Jt400DataQueueConsumer.java    |   2 +-
 .../component/jt400/Jt400MsgQueueConsumer.java     |   2 +-
 .../camel/component/kafka/KafkaConsumer.java       |  36 +-
 .../camel/component/kafka/KafkaEndpoint.java       |  21 -
 .../camel/component/kafka/KafkaConsumerTest.java   |  12 +
 .../camel/component/kafka/KafkaEndpointTest.java   |  75 ---
 .../config_maps/KubernetesConfigMapsConsumer.java  |   4 +-
 .../KubernetesCustomResourcesConsumer.java         |   4 +-
 .../deployments/KubernetesDeploymentsConsumer.java |   4 +-
 .../kubernetes/hpa/KubernetesHPAConsumer.java      |   4 +-
 .../namespaces/KubernetesNamespacesConsumer.java   |   4 +-
 .../kubernetes/nodes/KubernetesNodesConsumer.java  |   4 +-
 .../kubernetes/pods/KubernetesPodsConsumer.java    |   4 +-
 .../KubernetesReplicationControllersConsumer.java  |   5 +-
 .../services/KubernetesServicesConsumer.java       |   5 +-
 .../apache/camel/component/mail/MailConsumer.java  |  11 +-
 .../mail/MailConsumerAuthenticatorTest.java        |   9 +
 .../component/master/EndpointUriEncodingTest.java  |   2 +-
 .../component/milo/client/MiloClientConsumer.java  |   5 +-
 .../component/milo/server/MiloServerConsumer.java  |   4 +-
 .../apache/camel/component/mina/MinaConsumer.java  |  99 +--
 .../apache/camel/component/mina/MinaEndpoint.java  |  11 -
 .../mina/MinaTransferExchangeOptionTest.java       |   1 -
 .../camel/component/minio/MinioConsumer.java       |  36 +-
 .../camel/component/minio/MinioEndpoint.java       |  40 +-
 .../apache/camel/component/mllp/MllpEndpoint.java  |   2 +-
 .../component/mllp/MllpTcpServerConsumer.java      |   8 +-
 .../apache/camel/component/mock/MockEndpoint.java  |  52 +-
 .../component/mongodb/gridfs/GridFsConsumer.java   |   2 +-
 .../mongodb/MongoDbChangeStreamsConsumer.java      |   1 +
 .../mongodb/MongoDbChangeStreamsThread.java        |  14 +-
 .../camel/component/mongodb/MongoDbEndpoint.java   |  12 -
 .../component/mongodb/MongoDbTailingThread.java    |  14 +-
 .../camel/component/mybatis/MyBatisConsumer.java   |  21 +-
 .../mybatis/MyBatisConsumerIsolatedTest.java       |  53 --
 .../apache/camel/component/nats/NatsConsumer.java  |  40 +-
 .../component/netty/http/NettyHttpEndpoint.java    |  32 -
 .../component/netty/http/NettyHttpMessage.java     |  19 +-
 .../http/handlers/HttpServerChannelHandler.java    |  30 +
 .../http/NettyHttpSimplePooledExchangeTest.java    |  72 +++
 .../netty/DefaultServerInitializerFactory.java     |   1 -
 .../camel/component/netty/NettyEndpoint.java       |  10 +-
 .../netty/handlers/ServerChannelHandler.java       |  11 +-
 .../NettyTextlineInOnlyPooledExchangeTest.java     |  63 ++
 .../camel/component/nitrite/NitriteConsumer.java   |   3 +-
 .../apache/camel/component/nsq/NsqConsumer.java    |  13 +-
 .../camel/oaipmh/handler/AbstractHandler.java      |   9 +-
 .../org/apache/camel/oaipmh/handler/Harvester.java |  14 +-
 .../component/optaplanner/OptaPlannerConsumer.java |   8 +-
 .../component/paho/mqtt5/PahoMqtt5Consumer.java    |  14 +-
 .../component/paho/mqtt5/PahoMqtt5Endpoint.java    |  13 -
 .../apache/camel/component/paho/PahoConsumer.java  |  14 +-
 .../apache/camel/component/paho/PahoEndpoint.java  |  14 -
 .../slot/PgReplicationSlotConsumer.java            |   2 +-
 .../camel/component/pgevent/PgEventConsumer.java   |  10 +-
 .../apache/camel/pgevent/PgEventConsumerTest.java  |  30 +-
 .../http/vertx/VertxPlatformHttpConsumer.java      |  20 +-
 .../camel/component/pubnub/PubNubConsumer.java     |   9 +-
 .../component/pulsar/PulsarMessageListener.java    |  42 +-
 .../component/quickfixj/QuickfixjEndpoint.java     |  13 +-
 .../quickfixj/converter/QuickfixjConverters.java   |  23 +
 .../component/quickfixj/QuickfixjConsumerTest.java | 147 -----
 .../camel/component/rabbitmq/RabbitConsumer.java   |  11 +-
 .../camel/component/rabbitmq/RabbitMQConsumer.java |  10 +
 .../component/rabbitmq/RabbitMQConsumerTest.java   |  42 +-
 .../reactive/streams/ReactiveStreamsConsumer.java  |   4 +-
 .../component/salesforce/SalesforceConsumer.java   |   3 +-
 .../salesforce/SalesforceConsumerTest.java         |  15 +-
 .../component/scheduler/SchedulerConsumer.java     |  29 +-
 .../sip/listener/SipSubscriptionListener.java      |   8 +-
 .../apache/camel/component/sjms/SjmsEndpoint.java  |   8 +-
 .../apache/camel/component/sjms/SjmsMessage.java   |   8 +
 .../sjms/consumer/EndpointMessageListener.java     |  29 +-
 .../sjms/consumer/InOnlyConsumerQueueTest.java     |  11 +
 ...ueueTest.java => InOnlyPooledExchangeTest.java} |  23 +-
 .../camel/component/slack/SlackConsumer.java       |  22 +-
 .../camel/component/slack/SlackEndpoint.java       |  26 -
 .../smpp/MessageReceiverListenerImpl.java          |  24 +-
 .../apache/camel/component/smpp/SmppConsumer.java  |   3 +-
 .../apache/camel/component/smpp/SmppEndpoint.java  |  28 -
 .../smpp/MessageReceiverListenerImplTest.java      | 117 ----
 .../camel/component/smpp/SmppConsumerTest.java     |  12 +
 .../apache/camel/component/snmp/SnmpEndpoint.java  |  14 -
 .../camel/component/snmp/SnmpTrapConsumer.java     |  17 +-
 .../component/SoroushBotAbstractConsumer.java      |  38 +-
 .../component/SoroushBotMultiThreadConsumer.java   |   1 +
 .../component/SoroushBotSingleThreadConsumer.java  |   1 +
 .../camel/component/splunk/SplunkConsumer.java     |  28 +-
 .../integration/SpringIntegrationConsumer.java     |  17 +-
 .../integration/SpringIntegrationMessage.java      |   6 +
 .../springrabbit/EndpointMessageListener.java      |  33 +-
 ...MQConsumer.java => SpringRabbitMQConsumer.java} |   8 +-
 .../springrabbit/SpringRabbitMQEndpoint.java       |   2 +-
 .../RabbitMQConsumerPooledExchangeIntTest.java     |  70 +++
 .../camel/component/redis/RedisConsumer.java       |   8 +-
 .../spring/ws/SpringWebserviceConsumer.java        |  75 ++-
 .../spring/ws/SpringWebserviceMessage.java         |   6 +
 .../camel/component/cron/SpringCronConsumer.java   |   2 +-
 .../apache/camel/component/sql/SqlConsumer.java    |   9 +-
 .../apache/camel/component/ssh/SshConsumer.java    |  26 +-
 .../camel/component/stomp/StompEndpoint.java       |  10 +-
 .../camel/component/stream/StreamConsumer.java     |  12 +-
 .../camel/component/stream/StreamEndpoint.java     |   9 -
 .../camel/component/telegram/TelegramConsumer.java |  11 +-
 .../camel/component/telegram/TelegramEndpoint.java |  10 -
 .../thrift/server/ThriftMethodHandler.java         |  18 +-
 .../camel/component/timer/TimerConsumer.java       |  26 +-
 .../camel/component/undertow/UndertowConsumer.java |  33 +-
 .../camel/component/undertow/UndertowEndpoint.java |  20 -
 .../component/vertx/kafka/VertxKafkaConsumer.java  |  21 +-
 .../component/vertx/kafka/VertxKafkaEndpoint.java  |  21 -
 .../vertx/websocket/VertxWebsocketConsumer.java    |   5 +-
 .../camel/component/vertx/VertxConsumer.java       |   5 +-
 .../camel/websocket/jsr356/JSR356Consumer.java     |   2 +-
 .../component/websocket/WebsocketConsumer.java     |   2 +-
 .../component/websocket/WebsocketConsumerTest.java |  23 +-
 .../consumer/AbstractWordpressConsumer.java        |  17 +-
 .../apache/camel/component/xmpp/XmppConsumer.java  |  23 +-
 .../apache/camel/component/xmpp/XmppEndpoint.java  |   9 -
 .../yammer/YammerMessagePollingConsumer.java       |   3 +-
 .../yammer/YammerUserPollingConsumer.java          |   3 +-
 .../component/zookeeper/ZooKeeperConsumer.java     |   2 +-
 .../src/main/java/org/apache/camel/Consumer.java   |  24 +
 .../src/main/java/org/apache/camel/Endpoint.java   |  15 +-
 .../org/apache/camel/ExtendedCamelContext.java     |  22 +
 .../java/org/apache/camel/ExtendedExchange.java    |   8 +
 .../src/main/java/org/apache/camel/Message.java    |   7 +
 .../src/main/java/org/apache/camel/Ordered.java    |   2 +-
 .../main/java/org/apache/camel/PooledExchange.java |  71 +++
 .../java/org/apache/camel/spi/ExchangeFactory.java | 167 +++++
 .../apache/camel/spi/ExchangeFactoryManager.java   |  88 +++
 .../main/java/org/apache/camel/spi/UnitOfWork.java |  18 +-
 .../camel/impl/engine/AbstractCamelContext.java    |  47 ++
 .../camel/impl/engine/CamelInternalProcessor.java  |  20 +-
 .../camel/impl/engine/DefaultExchangeFactory.java  | 228 +++++++
 .../impl/engine/DefaultExchangeFactoryManager.java | 181 ++++++
 .../camel/impl/engine/DefaultUnitOfWork.java       |  77 ++-
 .../apache/camel/impl/engine/MDCUnitOfWork.java    |  13 +-
 .../camel/impl/engine/PooledExchangeFactory.java   | 195 ++++++
 .../camel/impl/engine/SimpleCamelContext.java      |  18 +
 .../camel/impl/ExtendedCamelContextConfigurer.java |  12 +
 .../camel/impl/lw/LightweightCamelContext.java     |  22 +
 .../impl/lw/LightweightRuntimeCamelContext.java    |  26 +
 .../component/dataset/DataSetTestEndpointTest.java |  12 +-
 .../camel/component/mock/MockAsBeanTest.java       |  12 +-
 .../apache/camel/processor/PooledExchangeTest.java |  85 +++
 .../RecipientListWithSimpleExpressionTest.java     |   2 +
 .../MainConfigurationPropertiesConfigurer.java     |  18 +
 .../camel-main-configuration-metadata.json         |   5 +-
 core/camel-main/src/main/docs/main.adoc            |   5 +-
 .../camel/main/DefaultConfigurationConfigurer.java |   6 +
 .../camel/main/DefaultConfigurationProperties.java |  75 ++-
 .../api/management/mbean/CamelOpenMBeanTypes.java  |  15 +
 .../mbean/ManagedExchangeFactoryManagerMBean.java  |  62 ++
 .../management/JmxManagementLifecycleStrategy.java |   4 +
 .../mbean/ManagedExchangeFactoryManager.java       | 144 +++++
 .../management/ManagedNonManagedServiceTest.java   |   2 +-
 .../management/ManagedPooledExchangeTest.java      | 132 ++++
 ...edProducerRouteAddRemoveRegisterAlwaysTest.java |   2 +-
 .../management/ManagedRouteAddRemoveTest.java      |   2 +-
 .../src/test/resources/log4j2.properties           |   2 +-
 ...{DefaultExchange.java => AbstractExchange.java} | 102 +--
 .../org/apache/camel/support/DefaultConsumer.java  |  48 +-
 .../org/apache/camel/support/DefaultEndpoint.java  |  15 +-
 .../org/apache/camel/support/DefaultExchange.java  | 681 +--------------------
 .../support/DefaultInterceptSendToEndpoint.java    |   5 +
 .../org/apache/camel/support/DefaultMessage.java   |   8 +
 .../camel/support/DefaultPooledExchange.java       | 168 +++++
 .../org/apache/camel/support/MessageSupport.java   |   7 +
 .../camel/support/PollingConsumerSupport.java      |  11 +
 .../org/apache/camel/support/UnitOfWorkHelper.java |  12 +-
 .../camel/support/component/ApiConsumerHelper.java |   8 +-
 docs/components/modules/others/pages/main.adoc     |   2 +
 .../ROOT/pages/camel-3x-upgrade-guide-3_9.adoc     |  17 +
 parent/pom.xml                                     |   2 +-
 316 files changed, 4409 insertions(+), 3245 deletions(-)

diff --git a/archetypes/camel-archetype-component/src/main/resources/archetype-resources/src/main/java/__name__Consumer.java b/archetypes/camel-archetype-component/src/main/resources/archetype-resources/src/main/java/__name__Consumer.java
index 0faa760..0721efd 100644
--- a/archetypes/camel-archetype-component/src/main/resources/archetype-resources/src/main/java/__name__Consumer.java
+++ b/archetypes/camel-archetype-component/src/main/resources/archetype-resources/src/main/java/__name__Consumer.java
@@ -57,7 +57,7 @@ public class ${name}Consumer extends DefaultConsumer {
     }
 
     private void onEventListener(final Object event) {
-        final Exchange exchange = endpoint.createExchange();
+        final Exchange exchange = createExchange(false);
 
         exchange.getIn().setBody("Hello World! The time is " + event);
 
@@ -70,6 +70,7 @@ public class ${name}Consumer extends DefaultConsumer {
             if (exchange.getException() != null) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
             }
+            releaseExchange(exchange, false);
         }
     }
 }
diff --git a/camel-dependencies/pom.xml b/camel-dependencies/pom.xml
index df7702a..f6a217c 100644
--- a/camel-dependencies/pom.xml
+++ b/camel-dependencies/pom.xml
@@ -314,7 +314,7 @@
     <jboss-marshalling-version>1.4.10.Final</jboss-marshalling-version>
     <jboss-transaction-spi.version>7.5.1.Final</jboss-transaction-spi.version>
     <jboss-xnio-version>3.3.8.Final</jboss-xnio-version>
-    <jbpm-version>7.49.0.Final</jbpm-version>
+    <jbpm-version>7.50.0.Final</jbpm-version>
     <jcache-bundle-version>1.1.0_1</jcache-bundle-version>
     <jclouds-google-guava-version>18.0</jclouds-google-guava-version>
     <jclouds-google-guava-version-range>[18.0,19.0)</jclouds-google-guava-version-range>
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index d443467..076f94a 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -33,6 +33,8 @@
     { "name": "camel.main.endpointBridgeErrorHandler", "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions occurred while the consumer is trying to pickup incoming messages, or the likes, will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN\/ERROR level and ignored. The default va [...]
     { "name": "camel.main.endpointLazyStartProducer", "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel's routing error handlers. Beware that when the first mes [...]
     { "name": "camel.main.endpointRuntimeStatisticsEnabled", "description": "Sets whether endpoint runtime statistics is enabled (gathers runtime usage of each incoming and outgoing endpoints). The default value is false.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean" },
+    { "name": "camel.main.exchangeFactory", "description": "Experimental: Controls whether to pool (reuse) exchanges or create new fresh exchanges (default). Using pooled will reduce JVM garbage collection overhead by avoiding to re-create Exchange instances per message each consumer receives.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "string", "javaType": "java.lang.String", "defaultValue": "default", "enum": [ "default", "pooled" ] },
+    { "name": "camel.main.exchangeFactoryStatisticsEnabled", "description": "Configures whether statistics is enabled on exchange factory.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean" },
     { "name": "camel.main.fileConfigurations", "description": "Directory to load additional configuration files that contains configuration values that takes precedence over any other configuration. This can be used to refer to files that may have secret configuration that has been mounted on the file system for containers. You can specify a pattern to load from sub directories and a name pattern such as \/var\/app\/secret\/.properties, multiple directories can be separated by comma.", " [...]
     { "name": "camel.main.inflightRepositoryBrowseEnabled", "description": "Sets whether the inflight repository should allow browsing each inflight exchange. This is by default disabled as there is a very slight performance overhead when enabled.", "sourceType": "org.apache.camel.main.DefaultConfigurationProperties", "type": "boolean", "javaType": "boolean" },
     { "name": "camel.main.javaRoutesExcludePattern", "description": "Used for exclusive filtering RouteBuilder classes which are collected from the registry or via classpath scanning. The exclusive filtering takes precedence over inclusive filtering. The pattern is using Ant-path style pattern. Multiple patterns can be specified separated by comma. For example to exclude all classes starting with Bar use: &#42;&#42;\/Bar&#42; To exclude all routes form a specific package use: com\/mycomp [...]
diff --git a/components/camel-ahc-ws/src/main/java/org/apache/camel/component/ahc/ws/WsConsumer.java b/components/camel-ahc-ws/src/main/java/org/apache/camel/component/ahc/ws/WsConsumer.java
index 1341bb4..8bf9923 100644
--- a/components/camel-ahc-ws/src/main/java/org/apache/camel/component/ahc/ws/WsConsumer.java
+++ b/components/camel-ahc-ws/src/main/java/org/apache/camel/component/ahc/ws/WsConsumer.java
@@ -68,7 +68,7 @@ public class WsConsumer extends DefaultConsumer {
     }
 
     private void sendMessageInternal(Object message) {
-        final Exchange exchange = getEndpoint().createExchange();
+        final Exchange exchange = createExchange(true);
 
         //TODO may set some headers with some meta info (e.g., socket info, unique-id for correlation purpose, etc0 
         // set the body
diff --git a/components/camel-apns/src/main/java/org/apache/camel/component/apns/ApnsConsumer.java b/components/camel-apns/src/main/java/org/apache/camel/component/apns/ApnsConsumer.java
index d0782a6..5d45e70 100644
--- a/components/camel-apns/src/main/java/org/apache/camel/component/apns/ApnsConsumer.java
+++ b/components/camel-apns/src/main/java/org/apache/camel/component/apns/ApnsConsumer.java
@@ -51,7 +51,7 @@ public class ApnsConsumer extends ScheduledPollConsumer {
         while (it.hasNext()) {
             InactiveDevice inactiveDevice = it.next();
 
-            Exchange e = getEndpoint().createExchange();
+            Exchange e = createExchange(true);
             e.getIn().setBody(inactiveDevice);
             getProcessor().process(e);
         }
diff --git a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Consumer.java b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Consumer.java
index 7e767eb..08b68d2 100644
--- a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Consumer.java
+++ b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Consumer.java
@@ -124,17 +124,18 @@ public class AS2Consumer extends AbstractApiConsumer<AS2ApiName, AS2Configuratio
                     = HttpMessageUtils.extractEdiPayload(request, as2ServerConnection.getDecryptingPrivateKey());
 
             // Set AS2 Interchange property and EDI message into body of input message.
-            Exchange exchange = getEndpoint().createExchange();
-            HttpCoreContext coreContext = HttpCoreContext.adapt(context);
-            exchange.setProperty(AS2Constants.AS2_INTERCHANGE, coreContext);
-            exchange.getIn().setBody(ediEntity.getEdiMessage());
+            Exchange exchange = createExchange(false);
 
             try {
+                HttpCoreContext coreContext = HttpCoreContext.adapt(context);
+                exchange.setProperty(AS2Constants.AS2_INTERCHANGE, coreContext);
+                exchange.getIn().setBody(ediEntity.getEdiMessage());
                 // send message to next processor in the route
                 getProcessor().process(exchange);
             } finally {
                 // check if an exception occurred and was not handled
                 exception = exchange.getException();
+                releaseExchange(exchange, false);
             }
         } catch (Exception e) {
             LOG.warn("Failed to process AS2 message", e);
diff --git a/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskConsumer.java b/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskConsumer.java
index 24c8368..e650178 100644
--- a/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskConsumer.java
+++ b/components/camel-asterisk/src/main/java/org/apache/camel/component/asterisk/AsteriskConsumer.java
@@ -62,14 +62,15 @@ public class AsteriskConsumer extends DefaultConsumer {
     private final class EventListener implements ManagerEventListener {
         @Override
         public void onManagerEvent(ManagerEvent event) {
-            Exchange exchange = endpoint.createExchange();
-            exchange.getIn().setHeader(AsteriskConstants.EVENT_NAME, event.getClass().getSimpleName());
-            exchange.getIn().setBody(event);
-
+            Exchange exchange = createExchange(false);
             try {
+                exchange.getIn().setHeader(AsteriskConstants.EVENT_NAME, event.getClass().getSimpleName());
+                exchange.getIn().setBody(event);
                 getProcessor().process(exchange);
             } catch (Exception e) {
                 getExceptionHandler().handleException("Error processing exchange.", exchange, e);
+            } finally {
+                releaseExchange(exchange, false);
             }
         }
     }
diff --git a/components/camel-atmos/src/main/java/org/apache/camel/component/atmos/integration/consumer/AtmosScheduledPollConsumer.java b/components/camel-atmos/src/main/java/org/apache/camel/component/atmos/integration/consumer/AtmosScheduledPollConsumer.java
index 0c1bb56..950415f 100644
--- a/components/camel-atmos/src/main/java/org/apache/camel/component/atmos/integration/consumer/AtmosScheduledPollConsumer.java
+++ b/components/camel-atmos/src/main/java/org/apache/camel/component/atmos/integration/consumer/AtmosScheduledPollConsumer.java
@@ -38,8 +38,6 @@ public abstract class AtmosScheduledPollConsumer extends ScheduledPollConsumer {
     /**
      * Lifecycle method invoked when the consumer has created. Internally create or reuse a connection to the low level
      * atmos client
-     * 
-     * @throws Exception
      */
     @Override
     protected void doStart() throws Exception {
@@ -53,8 +51,6 @@ public abstract class AtmosScheduledPollConsumer extends ScheduledPollConsumer {
 
     /**
      * Lifecycle method invoked when the consumer has destroyed. Erase the reference to the atmos low level client
-     * 
-     * @throws Exception
      */
     @Override
     protected void doStop() throws Exception {
diff --git a/components/camel-atmos/src/main/java/org/apache/camel/component/atmos/integration/consumer/AtmosScheduledPollGetConsumer.java b/components/camel-atmos/src/main/java/org/apache/camel/component/atmos/integration/consumer/AtmosScheduledPollGetConsumer.java
index e2d7f43..1f2fc02 100644
--- a/components/camel-atmos/src/main/java/org/apache/camel/component/atmos/integration/consumer/AtmosScheduledPollGetConsumer.java
+++ b/components/camel-atmos/src/main/java/org/apache/camel/component/atmos/integration/consumer/AtmosScheduledPollGetConsumer.java
@@ -32,17 +32,16 @@ public class AtmosScheduledPollGetConsumer extends AtmosScheduledPollConsumer {
     /**
      * Poll from an atmos remote path and put the result in the message exchange
      * 
-     * @return           number of messages polled
-     * @throws Exception
+     * @return number of messages polled
      */
     @Override
     protected int poll() throws Exception {
-        Exchange exchange = endpoint.createExchange();
-        AtmosResult result = AtmosAPIFacade.getInstance(configuration.getClient())
-                .get(configuration.getRemotePath());
-        result.populateExchange(exchange);
-
+        Exchange exchange = createExchange(false);
         try {
+            AtmosResult result = AtmosAPIFacade.getInstance(configuration.getClient())
+                    .get(configuration.getRemotePath());
+            result.populateExchange(exchange);
+
             // send message to next processor in the route
             getProcessor().process(exchange);
             return 1; // number of messages polled
@@ -51,6 +50,7 @@ public class AtmosScheduledPollGetConsumer extends AtmosScheduledPollConsumer {
             if (exchange.getException() != null) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
             }
+            releaseExchange(exchange, false);
         }
     }
 }
diff --git a/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/WebsocketConsumer.java b/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/WebsocketConsumer.java
index 8af4199..8957b6a 100644
--- a/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/WebsocketConsumer.java
+++ b/components/camel-atmosphere-websocket/src/main/java/org/apache/camel/component/atmosphere/websocket/WebsocketConsumer.java
@@ -84,7 +84,7 @@ public class WebsocketConsumer extends ServletConsumer {
     }
 
     public void sendMessage(final String connectionKey, Object message) {
-        final Exchange exchange = getEndpoint().createExchange();
+        final Exchange exchange = createExchange(true);
 
         // set header and body
         exchange.getIn().setHeader(WebsocketConstants.CONNECTION_KEY, connectionKey);
@@ -101,7 +101,7 @@ public class WebsocketConsumer extends ServletConsumer {
     }
 
     public void sendEventNotification(String connectionKey, int eventType) {
-        final Exchange exchange = getEndpoint().createExchange();
+        final Exchange exchange = createExchange(true);
 
         // set header
         exchange.getIn().setHeader(WebsocketConstants.CONNECTION_KEY, connectionKey);
@@ -122,7 +122,7 @@ public class WebsocketConsumer extends ServletConsumer {
     }
 
     public void sendNotDeliveredMessage(List<String> failedConnectionKeys, Object message) {
-        final Exchange exchange = getEndpoint().createExchange();
+        final Exchange exchange = createExchange(true);
 
         // set header and body
         exchange.getIn().setHeader(WebsocketConstants.CONNECTION_KEY_LIST, failedConnectionKeys);
diff --git a/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/map/AtomixMapConsumer.java b/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/map/AtomixMapConsumer.java
index d3ad3b7..854b411 100644
--- a/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/map/AtomixMapConsumer.java
+++ b/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/map/AtomixMapConsumer.java
@@ -83,7 +83,7 @@ public final class AtomixMapConsumer extends AbstractAtomixClientConsumer<Atomix
     // ********************************************
 
     private void onEvent(DistributedMap.EntryEvent<Object, Object> event) {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setHeader(AtomixClientConstants.EVENT_TYPE, event.type());
         exchange.getIn().setHeader(AtomixClientConstants.RESOURCE_KEY, event.entry().getKey());
 
diff --git a/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/messaging/AtomixMessagingConsumer.java b/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/messaging/AtomixMessagingConsumer.java
index 4371216..fdcccae 100644
--- a/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/messaging/AtomixMessagingConsumer.java
+++ b/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/messaging/AtomixMessagingConsumer.java
@@ -101,7 +101,7 @@ public final class AtomixMessagingConsumer extends AbstractAtomixClientConsumer<
     // ********************************************
 
     private void onMessage(Message<Object> message) {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setHeader(AtomixClientConstants.MESSAGE_ID, message.id());
 
         if (resultHeader == null) {
diff --git a/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/queue/AtomixQueueConsumer.java b/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/queue/AtomixQueueConsumer.java
index d90b38d..139d8a4 100644
--- a/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/queue/AtomixQueueConsumer.java
+++ b/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/queue/AtomixQueueConsumer.java
@@ -74,7 +74,7 @@ public final class AtomixQueueConsumer extends AbstractAtomixClientConsumer<Atom
     // ********************************************
 
     private void onEvent(DistributedQueue.ValueEvent<Object> event) {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setHeader(AtomixClientConstants.EVENT_TYPE, event.type());
 
         if (resultHeader == null) {
diff --git a/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/set/AtomixSetConsumer.java b/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/set/AtomixSetConsumer.java
index e35ad9d..10343b6 100644
--- a/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/set/AtomixSetConsumer.java
+++ b/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/set/AtomixSetConsumer.java
@@ -74,7 +74,7 @@ public final class AtomixSetConsumer extends AbstractAtomixClientConsumer<Atomix
     // ********************************************
 
     private void onEvent(DistributedSet.ValueEvent<Object> event) {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setHeader(AtomixClientConstants.EVENT_TYPE, event.type());
 
         if (resultHeader == null) {
diff --git a/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/value/AtomixValueConsumer.java b/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/value/AtomixValueConsumer.java
index 8fea9e6..1ec5efd 100644
--- a/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/value/AtomixValueConsumer.java
+++ b/components/camel-atomix/src/main/java/org/apache/camel/component/atomix/client/value/AtomixValueConsumer.java
@@ -73,7 +73,7 @@ public final class AtomixValueConsumer extends AbstractAtomixClientConsumer<Atom
     // ********************************************
 
     private void onEvent(DistributedValue.ChangeEvent<Object> event) {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setHeader(AtomixClientConstants.EVENT_TYPE, event.type());
         exchange.getIn().setHeader(AtomixClientConstants.RESOURCE_OLD_VALUE, event.oldValue());
 
diff --git a/components/camel-attachments/src/main/java/org/apache/camel/attachment/DefaultAttachmentMessage.java b/components/camel-attachments/src/main/java/org/apache/camel/attachment/DefaultAttachmentMessage.java
index fe87215..021f8e5 100644
--- a/components/camel-attachments/src/main/java/org/apache/camel/attachment/DefaultAttachmentMessage.java
+++ b/components/camel-attachments/src/main/java/org/apache/camel/attachment/DefaultAttachmentMessage.java
@@ -43,6 +43,11 @@ public final class DefaultAttachmentMessage implements AttachmentMessage {
     }
 
     @Override
+    public void reset() {
+        delegate.reset();
+    }
+
+    @Override
     public String getMessageId() {
         return delegate.getMessageId();
     }
diff --git a/components/camel-avro-rpc/src/main/java/org/apache/camel/component/avro/AvroEndpoint.java b/components/camel-avro-rpc/src/main/java/org/apache/camel/component/avro/AvroEndpoint.java
index d85e4dc..b5d555c 100644
--- a/components/camel-avro-rpc/src/main/java/org/apache/camel/component/avro/AvroEndpoint.java
+++ b/components/camel-avro-rpc/src/main/java/org/apache/camel/component/avro/AvroEndpoint.java
@@ -21,14 +21,11 @@ import java.util.Collections;
 import java.util.Map;
 
 import org.apache.avro.Protocol;
-import org.apache.avro.Schema;
 import org.apache.avro.reflect.ReflectData;
 import org.apache.camel.AsyncEndpoint;
 import org.apache.camel.Category;
 import org.apache.camel.Component;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
 import org.apache.camel.Processor;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -54,17 +51,6 @@ public abstract class AvroEndpoint extends DefaultEndpoint implements AsyncEndpo
         return false;
     }
 
-    public Exchange createExchange(Protocol.Message message, Object request) {
-        ExchangePattern pattern = ExchangePattern.InOut;
-        if (message.getResponse().getType().equals(Schema.Type.NULL)) {
-            pattern = ExchangePattern.InOnly;
-        }
-        Exchange exchange = createExchange(pattern);
-        exchange.getIn().setBody(request);
-        exchange.getIn().setHeader(AvroConstants.AVRO_MESSAGE_NAME, message.getName());
-        return exchange;
-    }
-
     @Override
     public Consumer createConsumer(Processor processor) throws Exception {
         AvroConsumer consumer = new AvroConsumer(this, processor);
diff --git a/components/camel-avro-rpc/src/main/java/org/apache/camel/component/avro/AvroListener.java b/components/camel-avro-rpc/src/main/java/org/apache/camel/component/avro/AvroListener.java
index 72d330b..b38bed1 100644
--- a/components/camel-avro-rpc/src/main/java/org/apache/camel/component/avro/AvroListener.java
+++ b/components/camel-avro-rpc/src/main/java/org/apache/camel/component/avro/AvroListener.java
@@ -28,6 +28,7 @@ import org.apache.avro.ipc.netty.NettyServer;
 import org.apache.avro.ipc.specific.SpecificResponder;
 import org.apache.avro.specific.SpecificData;
 import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
 import org.apache.camel.support.ExchangeHelper;
 import org.apache.commons.lang3.StringUtils;
 import org.eclipse.jetty.util.log.Log;
@@ -181,7 +182,7 @@ public class AvroListener {
      */
     private static Object processExchange(AvroConsumer consumer, Protocol.Message message, Object params) throws Exception {
         Object response;
-        Exchange exchange = consumer.getEndpoint().createExchange(message, params);
+        Exchange exchange = createExchange(consumer, message, params);
 
         try {
             consumer.getProcessor().process(exchange);
@@ -206,4 +207,17 @@ public class AvroListener {
         }
         return response;
     }
+
+    protected static Exchange createExchange(AvroConsumer consumer, Protocol.Message message, Object request) {
+        ExchangePattern pattern = ExchangePattern.InOut;
+        if (message.getResponse().getType().equals(Schema.Type.NULL)) {
+            pattern = ExchangePattern.InOnly;
+        }
+        Exchange exchange = consumer.createExchange(true);
+        exchange.setPattern(pattern);
+        exchange.getIn().setBody(request);
+        exchange.getIn().setHeader(AvroConstants.AVRO_MESSAGE_NAME, message.getName());
+        return exchange;
+    }
+
 }
diff --git a/components/camel-aws2-ddb/src/main/java/org/apache/camel/component/aws2/ddbstream/Ddb2StreamConsumer.java b/components/camel-aws2-ddb/src/main/java/org/apache/camel/component/aws2/ddbstream/Ddb2StreamConsumer.java
index 276195f..32bcb64 100644
--- a/components/camel-aws2-ddb/src/main/java/org/apache/camel/component/aws2/ddbstream/Ddb2StreamConsumer.java
+++ b/components/camel-aws2-ddb/src/main/java/org/apache/camel/component/aws2/ddbstream/Ddb2StreamConsumer.java
@@ -97,6 +97,12 @@ public class Ddb2StreamConsumer extends ScheduledBatchPollingConsumer {
         return processedExchanges;
     }
 
+    protected Exchange createExchange(Record record) {
+        Exchange ex = createExchange(true);
+        ex.getIn().setBody(record, Record.class);
+        return ex;
+    }
+
     private DynamoDbStreamsClient getClient() {
         return getEndpoint().getClient();
     }
@@ -130,7 +136,7 @@ public class Ddb2StreamConsumer extends ScheduledBatchPollingConsumer {
         for (Record record : records) {
             BigInteger recordSeqNum = new BigInteger(record.dynamodb().sequenceNumber());
             if (condition == null || condition.matches(providedSeqNum, recordSeqNum)) {
-                exchanges.add(getEndpoint().createExchange(record));
+                exchanges.add(createExchange(record));
             }
         }
         return exchanges;
diff --git a/components/camel-aws2-ddb/src/main/java/org/apache/camel/component/aws2/ddbstream/Ddb2StreamEndpoint.java b/components/camel-aws2-ddb/src/main/java/org/apache/camel/component/aws2/ddbstream/Ddb2StreamEndpoint.java
index 5c9b0a2..6f314ff 100644
--- a/components/camel-aws2-ddb/src/main/java/org/apache/camel/component/aws2/ddbstream/Ddb2StreamEndpoint.java
+++ b/components/camel-aws2-ddb/src/main/java/org/apache/camel/component/aws2/ddbstream/Ddb2StreamEndpoint.java
@@ -20,7 +20,6 @@ import java.net.URI;
 
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.spi.UriEndpoint;
@@ -34,7 +33,6 @@ import software.amazon.awssdk.http.SdkHttpConfigurationOption;
 import software.amazon.awssdk.http.apache.ApacheHttpClient;
 import software.amazon.awssdk.http.apache.ProxyConfiguration;
 import software.amazon.awssdk.regions.Region;
-import software.amazon.awssdk.services.dynamodb.model.Record;
 import software.amazon.awssdk.services.dynamodb.streams.DynamoDbStreamsClient;
 import software.amazon.awssdk.services.dynamodb.streams.DynamoDbStreamsClientBuilder;
 import software.amazon.awssdk.utils.AttributeMap;
@@ -69,13 +67,6 @@ public class Ddb2StreamEndpoint extends ScheduledPollEndpoint {
         return consumer;
     }
 
-    Exchange createExchange(Record record) {
-        Exchange ex = super.createExchange();
-        ex.getIn().setBody(record, Record.class);
-
-        return ex;
-    }
-
     @Override
     public void doStart() throws Exception {
         super.doStart();
diff --git a/components/camel-aws2-kinesis/src/main/java/org/apache/camel/component/aws2/kinesis/Kinesis2Consumer.java b/components/camel-aws2-kinesis/src/main/java/org/apache/camel/component/aws2/kinesis/Kinesis2Consumer.java
index e620181..fcda12b 100644
--- a/components/camel-aws2-kinesis/src/main/java/org/apache/camel/component/aws2/kinesis/Kinesis2Consumer.java
+++ b/components/camel-aws2-kinesis/src/main/java/org/apache/camel/component/aws2/kinesis/Kinesis2Consumer.java
@@ -75,7 +75,7 @@ public class Kinesis2Consumer extends ScheduledBatchPollingConsumer {
         // May cache the last successful sequence number, and pass it to the
         // getRecords request. That way, on the next poll, we start from where
         // we left off, however, I don't know what happens to subsequent
-        // exchanges when an earlier echangee fails.
+        // exchanges when an earlier exchange fails.
 
         currentShardIterator = result.nextShardIterator();
         if (isShardClosed) {
@@ -178,11 +178,20 @@ public class Kinesis2Consumer extends ScheduledBatchPollingConsumer {
     private Queue<Exchange> createExchanges(List<Record> records) {
         Queue<Exchange> exchanges = new ArrayDeque<>();
         for (Record record : records) {
-            exchanges.add(getEndpoint().createExchange(record));
+            exchanges.add(createExchange(record));
         }
         return exchanges;
     }
 
+    protected Exchange createExchange(Record record) {
+        Exchange exchange = createExchange(true);
+        exchange.getIn().setBody(record);
+        exchange.getIn().setHeader(Kinesis2Constants.APPROX_ARRIVAL_TIME, record.approximateArrivalTimestamp());
+        exchange.getIn().setHeader(Kinesis2Constants.PARTITION_KEY, record.partitionKey());
+        exchange.getIn().setHeader(Kinesis2Constants.SEQUENCE_NUMBER, record.sequenceNumber());
+        return exchange;
+    }
+
     private boolean hasSequenceNumber() {
         return !getEndpoint().getConfiguration().getSequenceNumber().isEmpty()
                 && (getEndpoint().getConfiguration().getIteratorType().equals(ShardIteratorType.AFTER_SEQUENCE_NUMBER)
diff --git a/components/camel-aws2-kinesis/src/main/java/org/apache/camel/component/aws2/kinesis/Kinesis2Endpoint.java b/components/camel-aws2-kinesis/src/main/java/org/apache/camel/component/aws2/kinesis/Kinesis2Endpoint.java
index ac0b0c4..ebe2e31 100644
--- a/components/camel-aws2-kinesis/src/main/java/org/apache/camel/component/aws2/kinesis/Kinesis2Endpoint.java
+++ b/components/camel-aws2-kinesis/src/main/java/org/apache/camel/component/aws2/kinesis/Kinesis2Endpoint.java
@@ -20,7 +20,6 @@ import java.net.URI;
 
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.spi.UriEndpoint;
@@ -36,7 +35,6 @@ import software.amazon.awssdk.http.apache.ProxyConfiguration;
 import software.amazon.awssdk.regions.Region;
 import software.amazon.awssdk.services.kinesis.KinesisClient;
 import software.amazon.awssdk.services.kinesis.KinesisClientBuilder;
-import software.amazon.awssdk.services.kinesis.model.Record;
 import software.amazon.awssdk.services.kinesis.model.ShardIteratorType;
 import software.amazon.awssdk.utils.AttributeMap;
 
@@ -102,15 +100,6 @@ public class Kinesis2Endpoint extends ScheduledPollEndpoint {
         return consumer;
     }
 
-    public Exchange createExchange(Record record) {
-        Exchange exchange = super.createExchange();
-        exchange.getIn().setBody(record);
-        exchange.getIn().setHeader(Kinesis2Constants.APPROX_ARRIVAL_TIME, record.approximateArrivalTimestamp());
-        exchange.getIn().setHeader(Kinesis2Constants.PARTITION_KEY, record.partitionKey());
-        exchange.getIn().setHeader(Kinesis2Constants.SEQUENCE_NUMBER, record.sequenceNumber());
-        return exchange;
-    }
-
     public KinesisClient getClient() {
         return kinesisClient;
     }
diff --git a/components/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Consumer.java b/components/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Consumer.java
index 2776fd0..a4e4fef 100644
--- a/components/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Consumer.java
+++ b/components/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Consumer.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.aws2.s3;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedList;
@@ -25,11 +26,14 @@ import java.util.Queue;
 
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
 import org.apache.camel.ExtendedExchange;
-import org.apache.camel.NoFactoryAvailableException;
+import org.apache.camel.Message;
 import org.apache.camel.Processor;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.Synchronization;
 import org.apache.camel.support.ScheduledBatchPollingConsumer;
+import org.apache.camel.support.SynchronizationAdapter;
 import org.apache.camel.util.CastUtils;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
@@ -52,6 +56,7 @@ import software.amazon.awssdk.services.s3.model.ListObjectsRequest;
 import software.amazon.awssdk.services.s3.model.ListObjectsResponse;
 import software.amazon.awssdk.services.s3.model.NoSuchKeyException;
 import software.amazon.awssdk.services.s3.model.S3Object;
+import software.amazon.awssdk.utils.IoUtils;
 
 /**
  * A Consumer of messages from the Amazon Web Service Simple Storage Service <a href="http://aws.amazon.com/s3/">AWS
@@ -64,7 +69,7 @@ public class AWS2S3Consumer extends ScheduledBatchPollingConsumer {
     private String marker;
     private transient String s3ConsumerToString;
 
-    public AWS2S3Consumer(AWS2S3Endpoint endpoint, Processor processor) throws NoFactoryAvailableException {
+    public AWS2S3Consumer(AWS2S3Endpoint endpoint, Processor processor) {
         super(endpoint, processor);
     }
 
@@ -180,7 +185,7 @@ public class AWS2S3Consumer extends ScheduledBatchPollingConsumer {
 
     protected Queue<Exchange> createExchanges(ResponseInputStream<GetObjectResponse> s3Object, String key) {
         Queue<Exchange> answer = new LinkedList<>();
-        Exchange exchange = getEndpoint().createExchange(s3Object, key);
+        Exchange exchange = createExchange(s3Object, key);
         answer.add(exchange);
         return answer;
     }
@@ -212,7 +217,7 @@ public class AWS2S3Consumer extends ScheduledBatchPollingConsumer {
 
                 if (includeS3Object(s3Object)) {
                     s3Objects.add(s3Object);
-                    Exchange exchange = getEndpoint().createExchange(s3Object, s3ObjectSummary.key());
+                    Exchange exchange = createExchange(s3Object, s3ObjectSummary.key());
                     answer.add(exchange);
                 } else {
                     // If includeFolders != true and the object is not included, it is safe to close the object here.
@@ -238,7 +243,6 @@ public class AWS2S3Consumer extends ScheduledBatchPollingConsumer {
      * @return          true to include, false to exclude
      */
     protected boolean includeS3Object(ResponseInputStream<GetObjectResponse> s3Object) {
-
         if (getConfiguration().isIncludeFolders()) {
             return true;
         } else {
@@ -365,6 +369,67 @@ public class AWS2S3Consumer extends ScheduledBatchPollingConsumer {
         return (AWS2S3Endpoint) super.getEndpoint();
     }
 
+    public Exchange createExchange(ResponseInputStream<GetObjectResponse> s3Object, String key) {
+        return createExchange(getEndpoint().getExchangePattern(), s3Object, key);
+    }
+
+    public Exchange createExchange(ExchangePattern pattern, ResponseInputStream<GetObjectResponse> s3Object, String key) {
+        LOG.trace("Getting object with key [{}] from bucket [{}]...", key, getConfiguration().getBucketName());
+
+        LOG.trace("Got object [{}]", s3Object);
+
+        Exchange exchange = createExchange(true);
+        exchange.setPattern(pattern);
+        Message message = exchange.getIn();
+
+        if (getConfiguration().isIncludeBody()) {
+            try {
+                message.setBody(IoUtils.toByteArray(s3Object));
+            } catch (IOException e) {
+                throw new RuntimeCamelException(e);
+            }
+        } else {
+            message.setBody(s3Object);
+        }
+
+        message.setHeader(AWS2S3Constants.KEY, key);
+        message.setHeader(AWS2S3Constants.BUCKET_NAME, getConfiguration().getBucketName());
+        message.setHeader(AWS2S3Constants.E_TAG, s3Object.response().eTag());
+        message.setHeader(AWS2S3Constants.LAST_MODIFIED, s3Object.response().lastModified());
+        message.setHeader(AWS2S3Constants.VERSION_ID, s3Object.response().versionId());
+        message.setHeader(AWS2S3Constants.CONTENT_TYPE, s3Object.response().contentType());
+        message.setHeader(AWS2S3Constants.CONTENT_LENGTH, s3Object.response().contentLength());
+        message.setHeader(AWS2S3Constants.CONTENT_ENCODING, s3Object.response().contentEncoding());
+        message.setHeader(AWS2S3Constants.CONTENT_DISPOSITION, s3Object.response().contentDisposition());
+        message.setHeader(AWS2S3Constants.CACHE_CONTROL, s3Object.response().cacheControl());
+        message.setHeader(AWS2S3Constants.SERVER_SIDE_ENCRYPTION, s3Object.response().serverSideEncryption());
+        message.setHeader(AWS2S3Constants.EXPIRATION_TIME, s3Object.response().expiration());
+        message.setHeader(AWS2S3Constants.REPLICATION_STATUS, s3Object.response().replicationStatus());
+        message.setHeader(AWS2S3Constants.STORAGE_CLASS, s3Object.response().storageClass());
+        message.setHeader(AWS2S3Constants.METADATA, s3Object.response().metadata());
+
+        /*
+         * If includeBody == true, it is safe to close the object here because the S3Object
+         * was consumed already. If includeBody != true, the caller is responsible for
+         * closing the stream once the body has been fully consumed or use the autoCloseBody
+         * configuration to automatically schedule the body closing at the end of exchange.
+         */
+        if (getConfiguration().isIncludeBody()) {
+            IOHelper.close(s3Object);
+        } else {
+            if (getConfiguration().isAutocloseBody()) {
+                exchange.adapt(ExtendedExchange.class).addOnCompletion(new SynchronizationAdapter() {
+                    @Override
+                    public void onDone(Exchange exchange) {
+                        IOHelper.close(s3Object);
+                    }
+                });
+            }
+        }
+
+        return exchange;
+    }
+
     @Override
     public String toString() {
         if (s3ConsumerToString == null) {
diff --git a/components/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Endpoint.java b/components/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Endpoint.java
index 8be1966..9cad4ee 100644
--- a/components/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Endpoint.java
+++ b/components/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/AWS2S3Endpoint.java
@@ -16,37 +16,25 @@
  */
 package org.apache.camel.component.aws2.s3;
 
-import java.io.IOException;
-
 import org.apache.camel.Category;
 import org.apache.camel.Component;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.ExtendedExchange;
-import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
-import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.aws2.s3.client.AWS2S3ClientFactory;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
 import org.apache.camel.support.ScheduledPollEndpoint;
-import org.apache.camel.support.SynchronizationAdapter;
-import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import software.amazon.awssdk.awscore.exception.AwsServiceException;
-import software.amazon.awssdk.core.ResponseInputStream;
 import software.amazon.awssdk.services.s3.S3Client;
 import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
-import software.amazon.awssdk.services.s3.model.GetObjectResponse;
 import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
 import software.amazon.awssdk.services.s3.model.PutBucketPolicyRequest;
-import software.amazon.awssdk.utils.IoUtils;
 
 /**
  * Store and retrieve objects from AWS S3 Storage Service using AWS SDK version 2.x.
@@ -152,66 +140,6 @@ public class AWS2S3Endpoint extends ScheduledPollEndpoint {
         super.doStop();
     }
 
-    public Exchange createExchange(ResponseInputStream<GetObjectResponse> s3Object, String key) {
-        return createExchange(getExchangePattern(), s3Object, key);
-    }
-
-    public Exchange createExchange(ExchangePattern pattern, ResponseInputStream<GetObjectResponse> s3Object, String key) {
-        LOG.trace("Getting object with key [{}] from bucket [{}]...", key, getConfiguration().getBucketName());
-
-        LOG.trace("Got object [{}]", s3Object);
-
-        Exchange exchange = super.createExchange(pattern);
-        Message message = exchange.getIn();
-
-        if (configuration.isIncludeBody()) {
-            try {
-                message.setBody(IoUtils.toByteArray(s3Object));
-            } catch (IOException e) {
-                throw new RuntimeCamelException(e);
-            }
-        } else {
-            message.setBody(s3Object);
-        }
-
-        message.setHeader(AWS2S3Constants.KEY, key);
-        message.setHeader(AWS2S3Constants.BUCKET_NAME, getConfiguration().getBucketName());
-        message.setHeader(AWS2S3Constants.E_TAG, s3Object.response().eTag());
-        message.setHeader(AWS2S3Constants.LAST_MODIFIED, s3Object.response().lastModified());
-        message.setHeader(AWS2S3Constants.VERSION_ID, s3Object.response().versionId());
-        message.setHeader(AWS2S3Constants.CONTENT_TYPE, s3Object.response().contentType());
-        message.setHeader(AWS2S3Constants.CONTENT_LENGTH, s3Object.response().contentLength());
-        message.setHeader(AWS2S3Constants.CONTENT_ENCODING, s3Object.response().contentEncoding());
-        message.setHeader(AWS2S3Constants.CONTENT_DISPOSITION, s3Object.response().contentDisposition());
-        message.setHeader(AWS2S3Constants.CACHE_CONTROL, s3Object.response().cacheControl());
-        message.setHeader(AWS2S3Constants.SERVER_SIDE_ENCRYPTION, s3Object.response().serverSideEncryption());
-        message.setHeader(AWS2S3Constants.EXPIRATION_TIME, s3Object.response().expiration());
-        message.setHeader(AWS2S3Constants.REPLICATION_STATUS, s3Object.response().replicationStatus());
-        message.setHeader(AWS2S3Constants.STORAGE_CLASS, s3Object.response().storageClass());
-        message.setHeader(AWS2S3Constants.METADATA, s3Object.response().metadata());
-
-        /*
-         * If includeBody == true, it is safe to close the object here because the S3Object
-         * was consumed already. If includeBody != true, the caller is responsible for
-         * closing the stream once the body has been fully consumed or use the autoCloseBody
-         * configuration to automatically schedule the body closing at the end of exchange.
-         */
-        if (configuration.isIncludeBody()) {
-            IOHelper.close(s3Object);
-        } else {
-            if (configuration.isAutocloseBody()) {
-                exchange.adapt(ExtendedExchange.class).addOnCompletion(new SynchronizationAdapter() {
-                    @Override
-                    public void onDone(Exchange exchange) {
-                        IOHelper.close(s3Object);
-                    }
-                });
-            }
-        }
-
-        return exchange;
-    }
-
     public AWS2S3Configuration getConfiguration() {
         return configuration;
     }
diff --git a/components/camel-aws2-sqs/src/main/java/org/apache/camel/component/aws2/sqs/Sqs2Consumer.java b/components/camel-aws2-sqs/src/main/java/org/apache/camel/component/aws2/sqs/Sqs2Consumer.java
index 660df45..3cc5cb7 100644
--- a/components/camel-aws2-sqs/src/main/java/org/apache/camel/component/aws2/sqs/Sqs2Consumer.java
+++ b/components/camel-aws2-sqs/src/main/java/org/apache/camel/component/aws2/sqs/Sqs2Consumer.java
@@ -18,17 +18,21 @@ package org.apache.camel.component.aws2.sqs;
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Queue;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
 import org.apache.camel.ExtendedExchange;
-import org.apache.camel.NoFactoryAvailableException;
+import org.apache.camel.Message;
 import org.apache.camel.Processor;
+import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.spi.Synchronization;
 import org.apache.camel.support.ScheduledBatchPollingConsumer;
 import org.apache.camel.util.CastUtils;
@@ -40,6 +44,7 @@ import software.amazon.awssdk.awscore.exception.AwsServiceException;
 import software.amazon.awssdk.services.sqs.SqsClient;
 import software.amazon.awssdk.services.sqs.model.ChangeMessageVisibilityRequest;
 import software.amazon.awssdk.services.sqs.model.DeleteMessageRequest;
+import software.amazon.awssdk.services.sqs.model.MessageAttributeValue;
 import software.amazon.awssdk.services.sqs.model.MessageNotInflightException;
 import software.amazon.awssdk.services.sqs.model.QueueDeletedRecentlyException;
 import software.amazon.awssdk.services.sqs.model.QueueDoesNotExistException;
@@ -60,7 +65,7 @@ public class Sqs2Consumer extends ScheduledBatchPollingConsumer {
     private Collection<String> attributeNames;
     private Collection<String> messageAttributeNames;
 
-    public Sqs2Consumer(Sqs2Endpoint endpoint, Processor processor) throws NoFactoryAvailableException {
+    public Sqs2Consumer(Sqs2Endpoint endpoint, Processor processor) {
         super(endpoint, processor);
 
         if (getConfiguration().getAttributeNames() != null) {
@@ -136,7 +141,7 @@ public class Sqs2Consumer extends ScheduledBatchPollingConsumer {
 
         Queue<Exchange> answer = new LinkedList<>();
         for (software.amazon.awssdk.services.sqs.model.Message message : messages) {
-            Exchange exchange = getEndpoint().createExchange(message);
+            Exchange exchange = createExchange(message);
             answer.add(exchange);
         }
 
@@ -282,6 +287,47 @@ public class Sqs2Consumer extends ScheduledBatchPollingConsumer {
         return (Sqs2Endpoint) super.getEndpoint();
     }
 
+    public Exchange createExchange(software.amazon.awssdk.services.sqs.model.Message msg) {
+        return createExchange(getEndpoint().getExchangePattern(), msg);
+    }
+
+    private Exchange createExchange(ExchangePattern pattern, software.amazon.awssdk.services.sqs.model.Message msg) {
+        Exchange exchange = createExchange(true);
+        exchange.setPattern(pattern);
+        Message message = exchange.getIn();
+        message.setBody(msg.body());
+        message.setHeaders(new HashMap<>(msg.attributesAsStrings()));
+        message.setHeader(Sqs2Constants.MESSAGE_ID, msg.messageId());
+        message.setHeader(Sqs2Constants.MD5_OF_BODY, msg.md5OfBody());
+        message.setHeader(Sqs2Constants.RECEIPT_HANDLE, msg.receiptHandle());
+        message.setHeader(Sqs2Constants.ATTRIBUTES, msg.attributes());
+        message.setHeader(Sqs2Constants.MESSAGE_ATTRIBUTES, msg.messageAttributes());
+
+        // Need to apply the SqsHeaderFilterStrategy this time
+        HeaderFilterStrategy headerFilterStrategy = getEndpoint().getHeaderFilterStrategy();
+        // add all sqs message attributes as camel message headers so that
+        // knowledge of
+        // the Sqs class MessageAttributeValue will not leak to the client
+        for (Map.Entry<String, MessageAttributeValue> entry : msg.messageAttributes().entrySet()) {
+            String header = entry.getKey();
+            Object value = translateValue(entry.getValue());
+            if (!headerFilterStrategy.applyFilterToExternalHeaders(header, value, exchange)) {
+                message.setHeader(header, value);
+            }
+        }
+        return exchange;
+    }
+
+    private static Object translateValue(MessageAttributeValue mav) {
+        Object result = null;
+        if (mav.stringValue() != null) {
+            result = mav.stringValue();
+        } else if (mav.binaryValue() != null) {
+            result = mav.binaryValue();
+        }
+        return result;
+    }
+
     @Override
     public String toString() {
         if (sqsConsumerToString == null) {
diff --git a/components/camel-aws2-sqs/src/main/java/org/apache/camel/component/aws2/sqs/Sqs2Endpoint.java b/components/camel-aws2-sqs/src/main/java/org/apache/camel/component/aws2/sqs/Sqs2Endpoint.java
index 2dc209c..1eb4014 100644
--- a/components/camel-aws2-sqs/src/main/java/org/apache/camel/component/aws2/sqs/Sqs2Endpoint.java
+++ b/components/camel-aws2-sqs/src/main/java/org/apache/camel/component/aws2/sqs/Sqs2Endpoint.java
@@ -21,13 +21,9 @@ import java.io.InputStream;
 import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Map.Entry;
 
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.component.aws2.sqs.client.Sqs2ClientFactory;
@@ -52,7 +48,6 @@ import software.amazon.awssdk.services.sqs.model.CreateQueueResponse;
 import software.amazon.awssdk.services.sqs.model.GetQueueUrlRequest;
 import software.amazon.awssdk.services.sqs.model.GetQueueUrlResponse;
 import software.amazon.awssdk.services.sqs.model.ListQueuesResponse;
-import software.amazon.awssdk.services.sqs.model.MessageAttributeValue;
 import software.amazon.awssdk.services.sqs.model.QueueAttributeName;
 import software.amazon.awssdk.services.sqs.model.QueueDoesNotExistException;
 import software.amazon.awssdk.services.sqs.model.SetQueueAttributesRequest;
@@ -343,36 +338,6 @@ public class Sqs2Endpoint extends ScheduledPollEndpoint implements HeaderFilterS
         super.doStop();
     }
 
-    public Exchange createExchange(software.amazon.awssdk.services.sqs.model.Message msg) {
-        return createExchange(getExchangePattern(), msg);
-    }
-
-    private Exchange createExchange(ExchangePattern pattern, software.amazon.awssdk.services.sqs.model.Message msg) {
-        Exchange exchange = super.createExchange(pattern);
-        Message message = exchange.getIn();
-        message.setBody(msg.body());
-        message.setHeaders(new HashMap<>(msg.attributesAsStrings()));
-        message.setHeader(Sqs2Constants.MESSAGE_ID, msg.messageId());
-        message.setHeader(Sqs2Constants.MD5_OF_BODY, msg.md5OfBody());
-        message.setHeader(Sqs2Constants.RECEIPT_HANDLE, msg.receiptHandle());
-        message.setHeader(Sqs2Constants.ATTRIBUTES, msg.attributes());
-        message.setHeader(Sqs2Constants.MESSAGE_ATTRIBUTES, msg.messageAttributes());
-
-        // Need to apply the SqsHeaderFilterStrategy this time
-        HeaderFilterStrategy headerFilterStrategy = getHeaderFilterStrategy();
-        // add all sqs message attributes as camel message headers so that
-        // knowledge of
-        // the Sqs class MessageAttributeValue will not leak to the client
-        for (Entry<String, MessageAttributeValue> entry : msg.messageAttributes().entrySet()) {
-            String header = entry.getKey();
-            Object value = translateValue(entry.getValue());
-            if (!headerFilterStrategy.applyFilterToExternalHeaders(header, value, exchange)) {
-                message.setHeader(header, value);
-            }
-        }
-        return exchange;
-    }
-
     public Sqs2Configuration getConfiguration() {
         return configuration;
     }
@@ -406,13 +371,4 @@ public class Sqs2Endpoint extends ScheduledPollEndpoint implements HeaderFilterS
         this.maxMessagesPerPoll = maxMessagesPerPoll;
     }
 
-    private Object translateValue(MessageAttributeValue mav) {
-        Object result = null;
-        if (mav.stringValue() != null) {
-            result = mav.stringValue();
-        } else if (mav.binaryValue() != null) {
-            result = mav.binaryValue();
-        }
-        return result;
-    }
 }
diff --git a/components/camel-azure-eventhubs/src/main/java/org/apache/camel/component/azure/eventhubs/EventHubsConsumer.java b/components/camel-azure-eventhubs/src/main/java/org/apache/camel/component/azure/eventhubs/EventHubsConsumer.java
index 0d27c8e..56ccee6 100644
--- a/components/camel-azure-eventhubs/src/main/java/org/apache/camel/component/azure/eventhubs/EventHubsConsumer.java
+++ b/components/camel-azure-eventhubs/src/main/java/org/apache/camel/component/azure/eventhubs/EventHubsConsumer.java
@@ -21,6 +21,7 @@ import com.azure.messaging.eventhubs.models.ErrorContext;
 import com.azure.messaging.eventhubs.models.EventContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExtendedExchange;
+import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.component.azure.eventhubs.client.EventHubsClientFactory;
 import org.apache.camel.spi.Synchronization;
@@ -71,8 +72,37 @@ public class EventHubsConsumer extends DefaultConsumer {
         return (EventHubsEndpoint) super.getEndpoint();
     }
 
+    private Exchange createAzureEventHubExchange(final EventContext eventContext) {
+        final Exchange exchange = createExchange(true);
+        final Message message = exchange.getIn();
+
+        // set body as byte[] and let camel typeConverters do the job to convert
+        message.setBody(eventContext.getEventData().getBody());
+        // set headers
+        message.setHeader(EventHubsConstants.PARTITION_ID, eventContext.getPartitionContext().getPartitionId());
+        message.setHeader(EventHubsConstants.PARTITION_KEY, eventContext.getEventData().getPartitionKey());
+        message.setHeader(EventHubsConstants.OFFSET, eventContext.getEventData().getOffset());
+        message.setHeader(EventHubsConstants.ENQUEUED_TIME, eventContext.getEventData().getEnqueuedTime());
+        message.setHeader(EventHubsConstants.SEQUENCE_NUMBER, eventContext.getEventData().getSequenceNumber());
+
+        return exchange;
+    }
+
+    private Exchange createAzureEventHubExchange(final ErrorContext errorContext) {
+        final Exchange exchange = createExchange(true);
+        final Message message = exchange.getIn();
+
+        // set headers
+        message.setHeader(EventHubsConstants.PARTITION_ID, errorContext.getPartitionContext().getPartitionId());
+
+        // set exception
+        exchange.setException(errorContext.getThrowable());
+
+        return exchange;
+    }
+
     private void onEventListener(final EventContext eventContext) {
-        final Exchange exchange = getEndpoint().createAzureEventHubExchange(eventContext);
+        final Exchange exchange = createAzureEventHubExchange(eventContext);
 
         // add exchange callback
         exchange.adapt(ExtendedExchange.class).addOnCompletion(new Synchronization() {
@@ -93,7 +123,7 @@ public class EventHubsConsumer extends DefaultConsumer {
     }
 
     private void onErrorListener(final ErrorContext errorContext) {
-        final Exchange exchange = getEndpoint().createAzureEventHubExchange(errorContext);
+        final Exchange exchange = createAzureEventHubExchange(errorContext);
 
         // log exception if an exception occurred and was not handled
         if (exchange.getException() != null) {
diff --git a/components/camel-azure-eventhubs/src/main/java/org/apache/camel/component/azure/eventhubs/EventHubsEndpoint.java b/components/camel-azure-eventhubs/src/main/java/org/apache/camel/component/azure/eventhubs/EventHubsEndpoint.java
index 061a277..b9010e8 100644
--- a/components/camel-azure-eventhubs/src/main/java/org/apache/camel/component/azure/eventhubs/EventHubsEndpoint.java
+++ b/components/camel-azure-eventhubs/src/main/java/org/apache/camel/component/azure/eventhubs/EventHubsEndpoint.java
@@ -16,13 +16,9 @@
  */
 package org.apache.camel.component.azure.eventhubs;
 
-import com.azure.messaging.eventhubs.models.ErrorContext;
-import com.azure.messaging.eventhubs.models.EventContext;
 import org.apache.camel.Category;
 import org.apache.camel.Component;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.spi.UriEndpoint;
@@ -71,32 +67,4 @@ public class EventHubsEndpoint extends DefaultEndpoint {
         this.configuration = configuration;
     }
 
-    public Exchange createAzureEventHubExchange(final EventContext eventContext) {
-        final Exchange exchange = createExchange();
-        final Message message = exchange.getIn();
-
-        // set body as byte[] and let camel typeConverters do the job to convert
-        message.setBody(eventContext.getEventData().getBody());
-        // set headers
-        message.setHeader(EventHubsConstants.PARTITION_ID, eventContext.getPartitionContext().getPartitionId());
-        message.setHeader(EventHubsConstants.PARTITION_KEY, eventContext.getEventData().getPartitionKey());
-        message.setHeader(EventHubsConstants.OFFSET, eventContext.getEventData().getOffset());
-        message.setHeader(EventHubsConstants.ENQUEUED_TIME, eventContext.getEventData().getEnqueuedTime());
-        message.setHeader(EventHubsConstants.SEQUENCE_NUMBER, eventContext.getEventData().getSequenceNumber());
-
-        return exchange;
-    }
-
-    public Exchange createAzureEventHubExchange(final ErrorContext errorContext) {
-        final Exchange exchange = createExchange();
-        final Message message = exchange.getIn();
-
-        // set headers
-        message.setHeader(EventHubsConstants.PARTITION_ID, errorContext.getPartitionContext().getPartitionId());
-
-        // set exception
-        exchange.setException(errorContext.getThrowable());
-
-        return exchange;
-    }
 }
diff --git a/components/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/BlobConsumer.java b/components/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/BlobConsumer.java
index e8bd3e2..00e9490 100644
--- a/components/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/BlobConsumer.java
+++ b/components/camel-azure-storage-blob/src/main/java/org/apache/camel/component/azure/storage/blob/BlobConsumer.java
@@ -81,7 +81,7 @@ public class BlobConsumer extends ScheduledBatchPollingConsumer {
         final BlobClientWrapper clientWrapper
                 = new BlobClientWrapper(blobContainerClient.getBlobClient(blobName));
         final BlobOperations operations = new BlobOperations(getEndpoint().getConfiguration(), clientWrapper);
-        final Exchange exchange = getEndpoint().createExchange();
+        final Exchange exchange = createExchange(true);
 
         BlobOperationResponse response;
         if (!ObjectHelper.isEmpty(getEndpoint().getConfiguration().getFileDir())) {
diff --git a/components/camel-azure-storage-datalake/src/main/java/org/apache/camel/component/azure/storage/datalake/DataLakeConsumer.java b/components/camel-azure-storage-datalake/src/main/java/org/apache/camel/component/azure/storage/datalake/DataLakeConsumer.java
index 3785ed5..915f7ee 100644
--- a/components/camel-azure-storage-datalake/src/main/java/org/apache/camel/component/azure/storage/datalake/DataLakeConsumer.java
+++ b/components/camel-azure-storage-datalake/src/main/java/org/apache/camel/component/azure/storage/datalake/DataLakeConsumer.java
@@ -102,7 +102,7 @@ class DataLakeConsumer extends ScheduledBatchPollingConsumer {
         final DataLakeFileClientWrapper clientWrapper
                 = new DataLakeFileClientWrapper(dataLakeFileSystemClient.getFileClient(fileName));
         final DataLakeFileOperations operations = new DataLakeFileOperations(getEndpoint().getConfiguration(), clientWrapper);
-        final Exchange exchange = getEndpoint().createExchange();
+        final Exchange exchange = createExchange(true);
 
         DataLakeOperationResponse response;
 
diff --git a/components/camel-azure-storage-queue/src/main/java/org/apache/camel/component/azure/storage/queue/QueueConsumer.java b/components/camel-azure-storage-queue/src/main/java/org/apache/camel/component/azure/storage/queue/QueueConsumer.java
index 28d2428..38d057f 100644
--- a/components/camel-azure-storage-queue/src/main/java/org/apache/camel/component/azure/storage/queue/QueueConsumer.java
+++ b/components/camel-azure-storage-queue/src/main/java/org/apache/camel/component/azure/storage/queue/QueueConsumer.java
@@ -27,6 +27,7 @@ import com.azure.storage.queue.models.QueueMessageItem;
 import com.azure.storage.queue.models.QueueStorageException;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExtendedExchange;
+import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.component.azure.storage.queue.client.QueueClientWrapper;
 import org.apache.camel.component.azure.storage.queue.operations.QueueOperations;
@@ -79,7 +80,7 @@ public class QueueConsumer extends ScheduledBatchPollingConsumer {
     private Queue<Exchange> createExchanges(final List<QueueMessageItem> messageItems) {
         return messageItems
                 .stream()
-                .map(queueMessageItem -> getEndpoint().createExchange(queueMessageItem))
+                .map(this::createExchange)
                 .collect(Collectors.toCollection(LinkedList::new));
     }
 
@@ -142,6 +143,16 @@ public class QueueConsumer extends ScheduledBatchPollingConsumer {
         return total;
     }
 
+    private Exchange createExchange(final QueueMessageItem messageItem) {
+        final Exchange exchange = createExchange(true);
+        final Message message = exchange.getIn();
+
+        message.setBody(messageItem.getMessageText());
+        message.setHeaders(QueueExchangeHeaders.createQueueExchangeHeadersFromQueueMessageItem(messageItem).toMap());
+
+        return exchange;
+    }
+
     /**
      * Strategy to delete the message after being processed.
      *
diff --git a/components/camel-azure-storage-queue/src/main/java/org/apache/camel/component/azure/storage/queue/QueueEndpoint.java b/components/camel-azure-storage-queue/src/main/java/org/apache/camel/component/azure/storage/queue/QueueEndpoint.java
index 525ae03..3fbaf5a 100644
--- a/components/camel-azure-storage-queue/src/main/java/org/apache/camel/component/azure/storage/queue/QueueEndpoint.java
+++ b/components/camel-azure-storage-queue/src/main/java/org/apache/camel/component/azure/storage/queue/QueueEndpoint.java
@@ -17,12 +17,9 @@
 package org.apache.camel.component.azure.storage.queue;
 
 import com.azure.storage.queue.QueueServiceClient;
-import com.azure.storage.queue.models.QueueMessageItem;
 import org.apache.camel.Category;
 import org.apache.camel.Component;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.component.azure.storage.queue.client.QueueClientFactory;
@@ -70,16 +67,6 @@ public class QueueEndpoint extends DefaultEndpoint {
                 ? configuration.getServiceClient() : QueueClientFactory.createQueueServiceClient(configuration);
     }
 
-    public Exchange createExchange(final QueueMessageItem messageItem) {
-        final Exchange exchange = createExchange();
-        final Message message = exchange.getIn();
-
-        message.setBody(messageItem.getMessageText());
-        message.setHeaders(QueueExchangeHeaders.createQueueExchangeHeadersFromQueueMessageItem(messageItem).toMap());
-
-        return exchange;
-    }
-
     /**
      * The component configurations
      */
diff --git a/components/camel-beanstalk/src/main/java/org/apache/camel/component/beanstalk/BeanstalkConsumer.java b/components/camel-beanstalk/src/main/java/org/apache/camel/component/beanstalk/BeanstalkConsumer.java
index b652e9e..a4ae7db 100644
--- a/components/camel-beanstalk/src/main/java/org/apache/camel/component/beanstalk/BeanstalkConsumer.java
+++ b/components/camel-beanstalk/src/main/java/org/apache/camel/component/beanstalk/BeanstalkConsumer.java
@@ -24,7 +24,6 @@ import com.surftools.BeanstalkClient.BeanstalkException;
 import com.surftools.BeanstalkClient.Client;
 import com.surftools.BeanstalkClient.Job;
 import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
 import org.apache.camel.ExtendedExchange;
 import org.apache.camel.Processor;
 import org.apache.camel.RuntimeCamelException;
@@ -92,7 +91,7 @@ public class BeanstalkConsumer extends ScheduledPollConsumer {
                     LOG.debug(String.format("Received job ID %d (data length %d)", job.getJobId(), job.getData().length));
                 }
 
-                final Exchange exchange = getEndpoint().createExchange(ExchangePattern.InOnly);
+                final Exchange exchange = createExchange(true);
                 exchange.getIn().setHeader(Headers.JOB_ID, job.getJobId());
                 exchange.getIn().setBody(job.getData(), byte[].class);
 
diff --git a/components/camel-cassandraql/src/main/java/org/apache/camel/component/cassandra/CassandraConsumer.java b/components/camel-cassandraql/src/main/java/org/apache/camel/component/cassandra/CassandraConsumer.java
index 07518f5..cc516d8 100644
--- a/components/camel-cassandraql/src/main/java/org/apache/camel/component/cassandra/CassandraConsumer.java
+++ b/components/camel-cassandraql/src/main/java/org/apache/camel/component/cassandra/CassandraConsumer.java
@@ -55,11 +55,11 @@ public class CassandraConsumer extends ScheduledPollConsumer {
         }
 
         // Create message from ResultSet
-        Exchange exchange = getEndpoint().createExchange();
-        Message message = exchange.getIn();
-        getEndpoint().fillMessage(resultSet, message);
+        Exchange exchange = createExchange(false);
 
         try {
+            Message message = exchange.getIn();
+            getEndpoint().fillMessage(resultSet, message);
             // send message to next processor in the route
             getProcessor().process(exchange);
             return 1; // number of messages polled
@@ -68,6 +68,7 @@ public class CassandraConsumer extends ScheduledPollConsumer {
             if (exchange.getException() != null) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
             }
+            releaseExchange(exchange, false);
         }
     }
 
diff --git a/components/camel-cmis/src/main/java/org/apache/camel/component/cmis/CMISConsumer.java b/components/camel-cmis/src/main/java/org/apache/camel/component/cmis/CMISConsumer.java
index a9e301c..afb7b63 100644
--- a/components/camel-cmis/src/main/java/org/apache/camel/component/cmis/CMISConsumer.java
+++ b/components/camel-cmis/src/main/java/org/apache/camel/component/cmis/CMISConsumer.java
@@ -58,7 +58,7 @@ public class CMISConsumer extends ScheduledPollConsumer {
 
     int sendExchangeWithPropsAndBody(Map<String, Object> properties, InputStream inputStream)
             throws Exception {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setHeaders(properties);
         exchange.getIn().setBody(inputStream);
         LOG.debug("Polling node: {}", properties.get("cmis:name"));
diff --git a/components/camel-coap/src/main/java/org/apache/camel/coap/CamelCoapResource.java b/components/camel-coap/src/main/java/org/apache/camel/coap/CamelCoapResource.java
index a1761be..948513b 100644
--- a/components/camel-coap/src/main/java/org/apache/camel/coap/CamelCoapResource.java
+++ b/components/camel-coap/src/main/java/org/apache/camel/coap/CamelCoapResource.java
@@ -91,7 +91,7 @@ final class CamelCoapResource extends CoapResource {
                 return;
             }
 
-            camelExchange = consumer.getEndpoint().createExchange();
+            camelExchange = consumer.createExchange(false);
             consumer.createUoW(camelExchange);
 
             OptionSet options = exchange.getRequest().getOptions();
@@ -144,6 +144,7 @@ final class CamelCoapResource extends CoapResource {
             if (camelExchange != null) {
                 consumer.doneUoW(camelExchange);
             }
+            consumer.releaseExchange(camelExchange, false);
         }
     }
 }
diff --git a/components/camel-cometd/src/main/java/org/apache/camel/component/cometd/CometdConsumer.java b/components/camel-cometd/src/main/java/org/apache/camel/component/cometd/CometdConsumer.java
index 3d2c498..84d09ab 100644
--- a/components/camel-cometd/src/main/java/org/apache/camel/component/cometd/CometdConsumer.java
+++ b/components/camel-cometd/src/main/java/org/apache/camel/component/cometd/CometdConsumer.java
@@ -98,17 +98,21 @@ public class CometdConsumer extends DefaultConsumer implements CometdProducerCon
 
             Message message = binding.createCamelMessage(endpoint.getCamelContext(), remote, cometdMessage, data);
 
-            Exchange exchange = endpoint.createExchange();
-            exchange.setIn(message);
+            Exchange exchange = consumer.createExchange(false);
+            try {
+                exchange.setIn(message);
 
-            consumer.getProcessor().process(exchange);
+                consumer.getProcessor().process(exchange);
 
-            if (ExchangeHelper.isOutCapable(exchange)) {
-                ServerChannel channel = getBayeux().getChannel(channelName);
-                ServerSession serverSession = getServerSession();
+                if (ExchangeHelper.isOutCapable(exchange)) {
+                    ServerChannel channel = getBayeux().getChannel(channelName);
+                    ServerSession serverSession = getServerSession();
 
-                ServerMessage.Mutable outMessage = binding.createCometdMessage(channel, serverSession, exchange.getOut());
-                remote.deliver(serverSession, outMessage);
+                    ServerMessage.Mutable outMessage = binding.createCometdMessage(channel, serverSession, exchange.getOut());
+                    remote.deliver(serverSession, outMessage);
+                }
+            } finally {
+                consumer.releaseExchange(exchange, false);
             }
         }
 
diff --git a/components/camel-cometd/src/test/java/org/apache/camel/component/cometd/CometdConsumerTest.java b/components/camel-cometd/src/test/java/org/apache/camel/component/cometd/CometdConsumerTest.java
index 545b621..51b7fcc 100644
--- a/components/camel-cometd/src/test/java/org/apache/camel/component/cometd/CometdConsumerTest.java
+++ b/components/camel-cometd/src/test/java/org/apache/camel/component/cometd/CometdConsumerTest.java
@@ -19,8 +19,10 @@ package org.apache.camel.component.cometd;
 import java.util.HashSet;
 import java.util.Set;
 
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Processor;
 import org.apache.camel.component.cometd.CometdConsumer.ConsumerService;
+import org.apache.camel.spi.ExchangeFactory;
 import org.cometd.bayeux.MarkedReference;
 import org.cometd.bayeux.server.LocalSession;
 import org.cometd.bayeux.server.ServerChannel;
@@ -35,6 +37,7 @@ import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
@@ -43,6 +46,10 @@ public class CometdConsumerTest {
     private static final String USER_NAME = "userName";
     private CometdConsumer testObj;
     @Mock
+    private ExtendedCamelContext context;
+    @Mock
+    private ExchangeFactory exchangeFactory;
+    @Mock
     private CometdEndpoint endpoint;
     @Mock
     private Processor processor;
@@ -65,6 +72,11 @@ public class CometdConsumerTest {
         when(bayeuxServerImpl.createChannelIfAbsent(ArgumentMatchers.isNull())).thenReturn(markedReferenceServerChannel);
         when(markedReferenceServerChannel.getReference()).thenReturn(serverChannel);
 
+        when(endpoint.getCamelContext()).thenReturn(context);
+        when(context.adapt(ExtendedCamelContext.class)).thenReturn(context);
+        when(context.getExchangeFactory()).thenReturn(exchangeFactory);
+        when(exchangeFactory.newExchangeFactory(any())).thenReturn(exchangeFactory);
+
         testObj = new CometdConsumer(endpoint, processor);
         testObj.setBayeux(bayeuxServerImpl);
 
diff --git a/components/camel-consul/src/main/java/org/apache/camel/component/consul/endpoint/ConsulEventConsumer.java b/components/camel-consul/src/main/java/org/apache/camel/component/consul/endpoint/ConsulEventConsumer.java
index 83b6661..25e6aaf 100644
--- a/components/camel-consul/src/main/java/org/apache/camel/component/consul/endpoint/ConsulEventConsumer.java
+++ b/components/camel-consul/src/main/java/org/apache/camel/component/consul/endpoint/ConsulEventConsumer.java
@@ -107,32 +107,34 @@ public final class ConsulEventConsumer extends AbstractConsulConsumer<EventClien
         private void onEvent(Event event) {
             LoggerFactory.getLogger(ConsulEventConsumer.this.getClass()).info("{}", event);
 
-            final Exchange exchange = endpoint.createExchange();
-            final Message message = exchange.getIn();
-
-            message.setHeader(ConsulConstants.CONSUL_KEY, key);
-            message.setHeader(ConsulConstants.CONSUL_RESULT, true);
-            message.setHeader(ConsulConstants.CONSUL_EVENT_ID, event.getId());
-            message.setHeader(ConsulConstants.CONSUL_EVENT_NAME, event.getName());
-            message.setHeader(ConsulConstants.CONSUL_EVENT_LTIME, event.getLTime());
-            message.setHeader(ConsulConstants.CONSUL_VERSION, event.getVersion());
-
-            if (event.getNodeFilter().isPresent()) {
-                message.setHeader(ConsulConstants.CONSUL_NODE_FILTER, event.getNodeFilter().get());
-            }
-            if (event.getServiceFilter().isPresent()) {
-                message.setHeader(ConsulConstants.CONSUL_SERVICE_FILTER, event.getServiceFilter().get());
-            }
-            if (event.getTagFilter().isPresent()) {
-                message.setHeader(ConsulConstants.CONSUL_TAG_FILTER, event.getTagFilter().get());
-            }
+            final Exchange exchange = createExchange(false);
+            try {
+                final Message message = exchange.getIn();
 
-            message.setBody(event.getPayload().orElse(null));
+                message.setHeader(ConsulConstants.CONSUL_KEY, key);
+                message.setHeader(ConsulConstants.CONSUL_RESULT, true);
+                message.setHeader(ConsulConstants.CONSUL_EVENT_ID, event.getId());
+                message.setHeader(ConsulConstants.CONSUL_EVENT_NAME, event.getName());
+                message.setHeader(ConsulConstants.CONSUL_EVENT_LTIME, event.getLTime());
+                message.setHeader(ConsulConstants.CONSUL_VERSION, event.getVersion());
+
+                if (event.getNodeFilter().isPresent()) {
+                    message.setHeader(ConsulConstants.CONSUL_NODE_FILTER, event.getNodeFilter().get());
+                }
+                if (event.getServiceFilter().isPresent()) {
+                    message.setHeader(ConsulConstants.CONSUL_SERVICE_FILTER, event.getServiceFilter().get());
+                }
+                if (event.getTagFilter().isPresent()) {
+                    message.setHeader(ConsulConstants.CONSUL_TAG_FILTER, event.getTagFilter().get());
+                }
+
+                message.setBody(event.getPayload().orElse(null));
 
-            try {
                 getProcessor().process(exchange);
             } catch (Exception e) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, e);
+            } finally {
+                releaseExchange(exchange, false);
             }
         }
 
diff --git a/components/camel-consul/src/main/java/org/apache/camel/component/consul/endpoint/ConsulKeyValueConsumer.java b/components/camel-consul/src/main/java/org/apache/camel/component/consul/endpoint/ConsulKeyValueConsumer.java
index a344336..e3adb3a 100644
--- a/components/camel-consul/src/main/java/org/apache/camel/component/consul/endpoint/ConsulKeyValueConsumer.java
+++ b/components/camel-consul/src/main/java/org/apache/camel/component/consul/endpoint/ConsulKeyValueConsumer.java
@@ -71,27 +71,30 @@ public final class ConsulKeyValueConsumer extends AbstractConsulConsumer<KeyValu
         }
 
         protected void onValue(Value value) {
-            final Exchange exchange = endpoint.createExchange();
-            final Message message = exchange.getIn();
-
-            message.setHeader(ConsulConstants.CONSUL_KEY, value.getKey());
-            message.setHeader(ConsulConstants.CONSUL_RESULT, true);
-            message.setHeader(ConsulConstants.CONSUL_FLAGS, value.getFlags());
-            message.setHeader(ConsulConstants.CONSUL_CREATE_INDEX, value.getCreateIndex());
-            message.setHeader(ConsulConstants.CONSUL_LOCK_INDEX, value.getLockIndex());
-            message.setHeader(ConsulConstants.CONSUL_MODIFY_INDEX, value.getModifyIndex());
-
-            if (value.getSession().isPresent()) {
-                message.setHeader(ConsulConstants.CONSUL_SESSION, value.getSession().get());
-            }
+            final Exchange exchange = createExchange(false);
+            try {
+                final Message message = exchange.getIn();
 
-            message.setBody(
-                    configuration.isValueAsString() ? value.getValueAsString().orElse(null) : value.getValue().orElse(null));
+                message.setHeader(ConsulConstants.CONSUL_KEY, value.getKey());
+                message.setHeader(ConsulConstants.CONSUL_RESULT, true);
+                message.setHeader(ConsulConstants.CONSUL_FLAGS, value.getFlags());
+                message.setHeader(ConsulConstants.CONSUL_CREATE_INDEX, value.getCreateIndex());
+                message.setHeader(ConsulConstants.CONSUL_LOCK_INDEX, value.getLockIndex());
+                message.setHeader(ConsulConstants.CONSUL_MODIFY_INDEX, value.getModifyIndex());
+
+                if (value.getSession().isPresent()) {
+                    message.setHeader(ConsulConstants.CONSUL_SESSION, value.getSession().get());
+                }
+
+                message.setBody(
+                        configuration.isValueAsString()
+                                ? value.getValueAsString().orElse(null) : value.getValue().orElse(null));
 
-            try {
                 getProcessor().process(exchange);
             } catch (Exception e) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, e);
+            } finally {
+                releaseExchange(exchange, false);
             }
         }
 
diff --git a/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConsumer.java b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConsumer.java
index 132723f..d69655f 100644
--- a/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConsumer.java
+++ b/components/camel-corda/src/main/java/org/apache/camel/component/corda/CordaConsumer.java
@@ -199,42 +199,42 @@ public class CordaConsumer extends DefaultConsumer {
 
     private void processFlowProcess(String x) {
         LOG.debug("processFlowProcess {}", x);
-        Exchange exchange = this.getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setBody(x);
         processEvent(exchange);
     }
 
     private void processTransactionMappingFeed(StateMachineTransactionMapping x) {
         LOG.debug("processTransactionMappingFeed {}", x);
-        Exchange exchange = this.getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setBody(x);
         processEvent(exchange);
     }
 
     private void proceedNetworkMapFeed(NetworkMapCache.MapChange x) {
         LOG.debug("proceedNetworkMapFeed {}", x);
-        Exchange exchange = this.getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setBody(x);
         processEvent(exchange);
     }
 
     private void processStateMachineUpdate(StateMachineUpdate x) {
         LOG.debug("processStateMachineUpdate {}", x);
-        Exchange exchange = this.getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setBody(x);
         processEvent(exchange);
     }
 
     private void processContractStateUpdate(Vault.Update<ContractState> x) {
         LOG.debug("processContractStateUpdate {}", x);
-        Exchange exchange = this.getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setBody(x);
         processEvent(exchange);
     }
 
     private void processError(Throwable throwable, String operation) {
         LOG.debug("processError for operation: " + operation + " " + throwable);
-        Exchange exchange = this.getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.setException(throwable);
         processEvent(exchange);
     }
@@ -244,7 +244,7 @@ public class CordaConsumer extends DefaultConsumer {
         try {
             getProcessor().process(exchange);
         } catch (Exception e) {
-            LOG.error("Error processing event ", e);
+            getExceptionHandler().handleException("Error processing event", e);
         }
     }
 
diff --git a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java
index ab6d5fc..18c2e98 100644
--- a/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java
+++ b/components/camel-couchbase/src/main/java/org/apache/camel/component/couchbase/CouchbaseConsumer.java
@@ -41,8 +41,8 @@ public class CouchbaseConsumer extends DefaultScheduledPollConsumer {
 
     private final CouchbaseEndpoint endpoint;
     private final Bucket bucket;
+    private final Collection collection;
     private ViewOptions viewOptions;
-    private Collection collection;
 
     public CouchbaseConsumer(CouchbaseEndpoint endpoint, Bucket client, Processor processor) {
         super(endpoint, processor);
@@ -60,13 +60,10 @@ public class CouchbaseConsumer extends DefaultScheduledPollConsumer {
         } else {
             this.collection = client.defaultCollection();
         }
-        init();
     }
 
     @Override
     protected void doInit() {
-
-        //   query.setIncludeDocs(true);
         this.viewOptions = ViewOptions.viewOptions();
         int limit = endpoint.getLimit();
         if (limit > 0) {
@@ -92,13 +89,11 @@ public class CouchbaseConsumer extends DefaultScheduledPollConsumer {
 
     @Override
     protected void doStart() throws Exception {
-        LOG.info("Starting Couchbase consumer");
         super.doStart();
     }
 
     @Override
     protected void doStop() throws Exception {
-        LOG.info("Stopping Couchbase consumer");
         super.doStop();
         if (bucket != null) {
             bucket.core().shutdown();
@@ -130,34 +125,36 @@ public class CouchbaseConsumer extends DefaultScheduledPollConsumer {
             String designDocumentName = endpoint.getDesignDocumentName();
             String viewName = endpoint.getViewName();
 
-            Exchange exchange = endpoint.createExchange();
-            exchange.getIn().setBody(doc);
-            exchange.getIn().setHeader(HEADER_ID, id);
-            exchange.getIn().setHeader(HEADER_KEY, key);
-            exchange.getIn().setHeader(HEADER_DESIGN_DOCUMENT_NAME, designDocumentName);
-            exchange.getIn().setHeader(HEADER_VIEWNAME, viewName);
-
-            if ("delete".equalsIgnoreCase(consumerProcessedStrategy)) {
-                if (LOG.isTraceEnabled()) {
-                    LOG.trace("Deleting doc with ID {}", id);
-                }
-
-                collection.remove(id);
-            } else if ("filter".equalsIgnoreCase(consumerProcessedStrategy)) {
-                if (LOG.isTraceEnabled()) {
-                    LOG.trace("Filtering out ID {}", id);
+            Exchange exchange = createExchange(false);
+            try {
+                exchange.getIn().setBody(doc);
+                exchange.getIn().setHeader(HEADER_ID, id);
+                exchange.getIn().setHeader(HEADER_KEY, key);
+                exchange.getIn().setHeader(HEADER_DESIGN_DOCUMENT_NAME, designDocumentName);
+                exchange.getIn().setHeader(HEADER_VIEWNAME, viewName);
+
+                if ("delete".equalsIgnoreCase(consumerProcessedStrategy)) {
+                    if (LOG.isTraceEnabled()) {
+                        LOG.trace("Deleting doc with ID {}", id);
+                    }
+
+                    collection.remove(id);
+                } else if ("filter".equalsIgnoreCase(consumerProcessedStrategy)) {
+                    if (LOG.isTraceEnabled()) {
+                        LOG.trace("Filtering out ID {}", id);
+                    }
+                    // add filter for already processed docs
+                } else {
+                    LOG.trace("No strategy set for already processed docs, beware of duplicates!");
                 }
-                // add filter for already processed docs
-            } else {
-                LOG.trace("No strategy set for already processed docs, beware of duplicates!");
-            }
 
-            logDetails(id, doc, key, designDocumentName, viewName, exchange);
+                logDetails(id, doc, key, designDocumentName, viewName, exchange);
 
-            try {
-                this.getProcessor().process(exchange);
+                getProcessor().process(exchange);
             } catch (Exception e) {
                 this.getExceptionHandler().handleException("Error processing exchange.", exchange, e);
+            } finally {
+                releaseExchange(exchange, false);
             }
         }
 
diff --git a/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbChangesetTracker.java b/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbChangesetTracker.java
index ac84831..14d145c 100644
--- a/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbChangesetTracker.java
+++ b/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbChangesetTracker.java
@@ -73,7 +73,7 @@ public class CouchDbChangesetTracker implements Runnable {
                         lastSequence = feed.getSeq();
                         JsonObject doc = feed.getDoc();
 
-                        Exchange exchange = endpoint.createExchange(lastSequence, feed.getId(), doc, feed.isDeleted());
+                        Exchange exchange = consumer.createExchange(lastSequence, feed.getId(), doc, feed.isDeleted());
                         if (LOG.isTraceEnabled()) {
                             LOG.trace("Created exchange [exchange={}, _id={}, seq={}",
                                     new Object[] { exchange, feed.getId(), lastSequence });
@@ -83,6 +83,8 @@ public class CouchDbChangesetTracker implements Runnable {
                             consumer.getProcessor().process(exchange);
                         } catch (Exception e) {
                             consumer.getExceptionHandler().handleException("Error processing exchange.", exchange, e);
+                        } finally {
+                            consumer.releaseExchange(exchange, false);
                         }
                     }
 
@@ -139,7 +141,4 @@ public class CouchDbChangesetTracker implements Runnable {
         changes.stop();
     }
 
-    public boolean isStopped() {
-        return stopped;
-    }
 }
diff --git a/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbConsumer.java b/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbConsumer.java
index 8064873..3a8e478 100644
--- a/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbConsumer.java
+++ b/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbConsumer.java
@@ -18,15 +18,13 @@ package org.apache.camel.component.couchdb;
 
 import java.util.concurrent.ExecutorService;
 
+import com.google.gson.JsonObject;
+import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.support.DefaultConsumer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class CouchDbConsumer extends DefaultConsumer {
 
-    private static final Logger LOG = LoggerFactory.getLogger(CouchDbConsumer.class);
-
     private final CouchDbClientWrapper couchClient;
     private final CouchDbEndpoint endpoint;
     private ExecutorService executor;
@@ -38,10 +36,20 @@ public class CouchDbConsumer extends DefaultConsumer {
         this.endpoint = endpoint;
     }
 
+    public Exchange createExchange(String seq, String id, JsonObject obj, boolean deleted) {
+        Exchange exchange = createExchange(false);
+        exchange.getIn().setHeader(CouchDbConstants.HEADER_DATABASE, endpoint.getDatabase());
+        exchange.getIn().setHeader(CouchDbConstants.HEADER_SEQ, seq);
+        exchange.getIn().setHeader(CouchDbConstants.HEADER_DOC_ID, id);
+        exchange.getIn().setHeader(CouchDbConstants.HEADER_DOC_REV, obj.get("_rev").getAsString());
+        exchange.getIn().setHeader(CouchDbConstants.HEADER_METHOD, deleted ? "DELETE" : "UPDATE");
+        exchange.getIn().setBody(obj);
+        return exchange;
+    }
+
     @Override
     protected void doStart() throws Exception {
         super.doStart();
-        LOG.info("Starting CouchDB consumer");
 
         executor = endpoint.getCamelContext().getExecutorServiceManager().newFixedThreadPool(this, endpoint.getEndpointUri(),
                 1);
@@ -52,7 +60,6 @@ public class CouchDbConsumer extends DefaultConsumer {
     @Override
     protected void doStop() throws Exception {
         super.doStop();
-        LOG.info("Stopping CouchDB consumer");
         if (task != null) {
             task.stop();
         }
diff --git a/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbEndpoint.java b/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbEndpoint.java
index 1137976..e9c6078 100644
--- a/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbEndpoint.java
+++ b/components/camel-couchdb/src/main/java/org/apache/camel/component/couchdb/CouchDbEndpoint.java
@@ -18,10 +18,8 @@ package org.apache.camel.component.couchdb;
 
 import java.net.URI;
 
-import com.google.gson.JsonObject;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.spi.Metadata;
@@ -112,17 +110,6 @@ public class CouchDbEndpoint extends DefaultEndpoint {
         return new CouchDbProducer(this, createClient());
     }
 
-    public Exchange createExchange(String seq, String id, JsonObject obj, boolean deleted) {
-        Exchange exchange = super.createExchange();
-        exchange.getIn().setHeader(CouchDbConstants.HEADER_DATABASE, database);
-        exchange.getIn().setHeader(CouchDbConstants.HEADER_SEQ, seq);
-        exchange.getIn().setHeader(CouchDbConstants.HEADER_DOC_ID, id);
-        exchange.getIn().setHeader(CouchDbConstants.HEADER_DOC_REV, obj.get("_rev").getAsString());
-        exchange.getIn().setHeader(CouchDbConstants.HEADER_METHOD, deleted ? "DELETE" : "UPDATE");
-        exchange.getIn().setBody(obj);
-        return exchange;
-    }
-
     protected CouchDbClientWrapper createClient() {
         return new CouchDbClientWrapper(
                 new CouchDbClient(database, createDatabase, protocol, hostname, port, username, password));
diff --git a/components/camel-couchdb/src/test/java/org/apache/camel/component/couchdb/CouchDbChangesetTrackerTest.java b/components/camel-couchdb/src/test/java/org/apache/camel/component/couchdb/CouchDbChangesetTrackerTest.java
index 018f8aa..7ae1c49 100644
--- a/components/camel-couchdb/src/test/java/org/apache/camel/component/couchdb/CouchDbChangesetTrackerTest.java
+++ b/components/camel-couchdb/src/test/java/org/apache/camel/component/couchdb/CouchDbChangesetTrackerTest.java
@@ -93,18 +93,18 @@ public class CouchDbChangesetTrackerTest {
         when(row3.getId()).thenReturn("id3");
         when(changes.hasNext()).thenReturn(true, true, true, false);
         when(changes.next()).thenReturn(row1, row2, row3);
-        when(endpoint.createExchange("seq1", "id1", null, false)).thenReturn(exchange1);
-        when(endpoint.createExchange("seq2", "id2", null, false)).thenReturn(exchange2);
-        when(endpoint.createExchange("seq3", "id3", null, false)).thenReturn(exchange3);
+        when(consumer.createExchange("seq1", "id1", null, false)).thenReturn(exchange1);
+        when(consumer.createExchange("seq2", "id2", null, false)).thenReturn(exchange2);
+        when(consumer.createExchange("seq3", "id3", null, false)).thenReturn(exchange3);
         when(consumer.getProcessor()).thenReturn(processor);
 
         tracker.run();
 
-        verify(endpoint).createExchange("seq1", "id1", null, false);
+        verify(consumer).createExchange("seq1", "id1", null, false);
         verify(processor).process(exchange1);
-        verify(endpoint).createExchange("seq2", "id2", null, false);
+        verify(consumer).createExchange("seq2", "id2", null, false);
         verify(processor).process(exchange2);
-        verify(endpoint).createExchange("seq3", "id3", null, false);
+        verify(consumer).createExchange("seq3", "id3", null, false);
         verify(processor).process(exchange3);
     }
 
@@ -116,7 +116,7 @@ public class CouchDbChangesetTrackerTest {
 
         tracker.run();
 
-        verify(endpoint).createExchange("seq1", "id1", null, false);
+        verify(consumer).createExchange("seq1", "id1", null, false);
         verify(processor).process(ArgumentMatchers.isNull());
     }
 }
diff --git a/components/camel-couchdb/src/test/java/org/apache/camel/component/couchdb/CouchDbEndpointTest.java b/components/camel-couchdb/src/test/java/org/apache/camel/component/couchdb/CouchDbEndpointTest.java
index b5d09ea..09a8d78 100644
--- a/components/camel-couchdb/src/test/java/org/apache/camel/component/couchdb/CouchDbEndpointTest.java
+++ b/components/camel-couchdb/src/test/java/org/apache/camel/component/couchdb/CouchDbEndpointTest.java
@@ -16,11 +16,6 @@
  */
 package org.apache.camel.component.couchdb;
 
-import java.util.UUID;
-
-import com.google.gson.JsonObject;
-import org.apache.camel.Exchange;
-import org.apache.camel.impl.DefaultCamelContext;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -30,28 +25,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 public class CouchDbEndpointTest {
 
     @Test
-    void testCreateCouchExchangeHeadersAreSet() throws Exception {
-        try (CouchDbEndpoint endpoint = new CouchDbEndpoint(
-                "couchdb:http://localhost/db", "http://localhost/db", new CouchDbComponent(new DefaultCamelContext()))) {
-
-            String id = UUID.randomUUID().toString();
-            String rev = UUID.randomUUID().toString();
-            String seq = "seq123";
-
-            JsonObject doc = new JsonObject();
-            doc.addProperty("_id", id);
-            doc.addProperty("_rev", rev);
-
-            Exchange exchange = endpoint.createExchange(seq, id, doc, false);
-            assertEquals(id, exchange.getIn().getHeader(CouchDbConstants.HEADER_DOC_ID));
-            assertEquals(rev, exchange.getIn().getHeader(CouchDbConstants.HEADER_DOC_REV));
-            assertEquals(seq, exchange.getIn().getHeader(CouchDbConstants.HEADER_SEQ));
-            assertEquals("UPDATE", exchange.getIn().getHeader(CouchDbConstants.HEADER_METHOD));
-            assertEquals("db", exchange.getIn().getHeader(CouchDbConstants.HEADER_DATABASE));
-        }
-    }
-
-    @Test
     void assertSingleton() throws Exception {
         try (CouchDbEndpoint endpoint
                 = new CouchDbEndpoint("couchdb:http://localhost/db", "http://localhost/db", new CouchDbComponent())) {
diff --git a/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetConsumer.java b/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetConsumer.java
index 43fbb4b..3fb132e 100644
--- a/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetConsumer.java
+++ b/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetConsumer.java
@@ -20,6 +20,7 @@ import java.util.concurrent.ExecutorService;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
+import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.spi.CamelLogger;
 import org.apache.camel.support.DefaultConsumer;
@@ -42,11 +43,6 @@ public class DataSetConsumer extends DefaultConsumer {
     }
 
     @Override
-    protected void doInit() throws Exception {
-        super.doInit();
-    }
-
-    @Override
     protected void doStart() throws Exception {
         super.doStart();
 
@@ -86,10 +82,27 @@ public class DataSetConsumer extends DefaultConsumer {
         }
     }
 
+    /**
+     * Creates a message exchange for the given index in the {@link DataSet}
+     */
+    protected Exchange createExchange(long messageIndex) throws Exception {
+        Exchange exchange = createExchange(false);
+
+        endpoint.getDataSet().populateMessage(exchange, messageIndex);
+
+        if (!endpoint.getDataSetIndex().equals("off")) {
+            Message in = exchange.getIn();
+            in.setHeader(Exchange.DATASET_INDEX, messageIndex);
+        }
+
+        return exchange;
+    }
+
     protected void sendMessages(long startIndex, long endIndex) {
-        try {
-            for (long i = startIndex; i < endIndex; i++) {
-                Exchange exchange = endpoint.createExchange(i);
+        for (long i = startIndex; i < endIndex; i++) {
+            Exchange exchange = null;
+            try {
+                exchange = createExchange(i);
                 getProcessor().process(exchange);
 
                 try {
@@ -104,9 +117,11 @@ public class DataSetConsumer extends DefaultConsumer {
                 if (reporter != null) {
                     reporter.process(exchange);
                 }
+            } catch (Exception e) {
+                handleException(e);
+            } finally {
+                releaseExchange(exchange, false);
             }
-        } catch (Exception e) {
-            handleException(e);
         }
     }
 
diff --git a/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetEndpoint.java b/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetEndpoint.java
index 1f13b95..bc53fdb 100644
--- a/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetEndpoint.java
+++ b/components/camel-dataset/src/main/java/org/apache/camel/component/dataset/DataSetEndpoint.java
@@ -102,7 +102,9 @@ public class DataSetEndpoint extends MockEndpoint implements Service {
     @Override
     public void reset() {
         super.reset();
-        receivedCounter.set(0);
+        if (receivedCounter != null) {
+            receivedCounter.set(0);
+        }
     }
 
     @Override
diff --git a/components/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumer.java b/components/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumer.java
index dee39dd..2ed84a8 100644
--- a/components/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumer.java
+++ b/components/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumConsumer.java
@@ -74,7 +74,7 @@ public class DebeziumConsumer extends DefaultConsumer {
     }
 
     private void onEventListener(final ChangeEvent<SourceRecord, SourceRecord> event) {
-        final Exchange exchange = endpoint.createDbzExchange(event.value());
+        final Exchange exchange = endpoint.createDbzExchange(this, event.value());
 
         try {
             // send message to next processor in the route
@@ -87,6 +87,7 @@ public class DebeziumConsumer extends DefaultConsumer {
                 getExceptionHandler().handleException("Error processing exchange", exchange,
                         exchange.getException());
             }
+            releaseExchange(exchange, false);
         }
     }
 }
diff --git a/components/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumEndpoint.java b/components/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumEndpoint.java
index 10d5a36..9cb5e1a 100644
--- a/components/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumEndpoint.java
+++ b/components/camel-debezium-common/camel-debezium-common-component/src/main/java/org/apache/camel/component/debezium/DebeziumEndpoint.java
@@ -63,8 +63,13 @@ public abstract class DebeziumEndpoint<C extends EmbeddedDebeziumConfiguration>
                 "DebeziumConsumer");
     }
 
-    public Exchange createDbzExchange(final SourceRecord record) {
-        final Exchange exchange = super.createExchange();
+    public Exchange createDbzExchange(DebeziumConsumer consumer, final SourceRecord record) {
+        final Exchange exchange;
+        if (consumer != null) {
+            exchange = consumer.createExchange(false);
+        } else {
+            exchange = super.createExchange();
+        }
 
         final Message message = exchange.getIn();
 
diff --git a/components/camel-debezium-common/camel-debezium-common-component/src/test/java/org/apache/camel/component/debezium/DebeziumEndpointTest.java b/components/camel-debezium-common/camel-debezium-common-component/src/test/java/org/apache/camel/component/debezium/DebeziumEndpointTest.java
index 853e316..4c9c4ce 100644
--- a/components/camel-debezium-common/camel-debezium-common-component/src/test/java/org/apache/camel/component/debezium/DebeziumEndpointTest.java
+++ b/components/camel-debezium-common/camel-debezium-common-component/src/test/java/org/apache/camel/component/debezium/DebeziumEndpointTest.java
@@ -76,7 +76,7 @@ public class DebeziumEndpointTest {
     void testIfCreatesExchangeFromSourceCreateRecord() {
         final SourceRecord sourceRecord = createCreateRecord();
 
-        final Exchange exchange = debeziumEndpoint.createDbzExchange(sourceRecord);
+        final Exchange exchange = debeziumEndpoint.createDbzExchange(null, sourceRecord);
         final Message inMessage = exchange.getIn();
 
         assertNotNull(exchange);
@@ -102,7 +102,7 @@ public class DebeziumEndpointTest {
     void testIfCreatesExchangeFromSourceDeleteRecord() {
         final SourceRecord sourceRecord = createDeleteRecord();
 
-        final Exchange exchange = debeziumEndpoint.createDbzExchange(sourceRecord);
+        final Exchange exchange = debeziumEndpoint.createDbzExchange(null, sourceRecord);
         final Message inMessage = exchange.getIn();
 
         assertNotNull(exchange);
@@ -123,7 +123,7 @@ public class DebeziumEndpointTest {
     void testIfCreatesExchangeFromSourceDeleteRecordWithNull() {
         final SourceRecord sourceRecord = createDeleteRecordWithNull();
 
-        final Exchange exchange = debeziumEndpoint.createDbzExchange(sourceRecord);
+        final Exchange exchange = debeziumEndpoint.createDbzExchange(null, sourceRecord);
         final Message inMessage = exchange.getIn();
 
         assertNotNull(exchange);
@@ -141,7 +141,7 @@ public class DebeziumEndpointTest {
     void testIfCreatesExchangeFromSourceUpdateRecord() {
         final SourceRecord sourceRecord = createUpdateRecord();
 
-        final Exchange exchange = debeziumEndpoint.createDbzExchange(sourceRecord);
+        final Exchange exchange = debeziumEndpoint.createDbzExchange(null, sourceRecord);
         final Message inMessage = exchange.getIn();
 
         assertNotNull(exchange);
@@ -166,7 +166,7 @@ public class DebeziumEndpointTest {
     void testIfCreatesExchangeFromSourceRecordOtherThanStruct() {
         final SourceRecord sourceRecord = createStringRecord();
 
-        final Exchange exchange = debeziumEndpoint.createDbzExchange(sourceRecord);
+        final Exchange exchange = debeziumEndpoint.createDbzExchange(null, sourceRecord);
         final Message inMessage = exchange.getIn();
 
         assertNotNull(exchange);
@@ -184,7 +184,7 @@ public class DebeziumEndpointTest {
     void testIfHandlesUnknownSchema() {
         final SourceRecord sourceRecord = createUnknownUnnamedSchemaRecord();
 
-        final Exchange exchange = debeziumEndpoint.createDbzExchange(sourceRecord);
+        final Exchange exchange = debeziumEndpoint.createDbzExchange(null, sourceRecord);
         final Message inMessage = exchange.getIn();
 
         assertNotNull(exchange);
diff --git a/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorConsumer.java b/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorConsumer.java
index 77b74e4..b9734af 100644
--- a/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorConsumer.java
+++ b/components/camel-disruptor/src/main/java/org/apache/camel/component/disruptor/DisruptorConsumer.java
@@ -192,6 +192,17 @@ public class DisruptorConsumer extends ServiceSupport implements Consumer, Suspe
         }
     }
 
+    @Override
+    public Exchange createExchange(boolean autoRelease) {
+        // noop
+        return null;
+    }
+
+    @Override
+    public void releaseExchange(Exchange exchange, boolean autoRelease) {
+        // noop
+    }
+
     /**
      * Implementation of the {@link LifecycleAwareExchangeEventHandler} interface that passes all Exchanges to the
      * {@link Processor} registered at this {@link DisruptorConsumer}.
diff --git a/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerEventsConsumer.java b/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerEventsConsumer.java
index 005c085..4ab51f6 100644
--- a/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerEventsConsumer.java
+++ b/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerEventsConsumer.java
@@ -88,24 +88,19 @@ public class DockerEventsConsumer extends DefaultConsumer {
         public void onNext(Event event) {
             LOG.debug("Received Docker Event: {}", event);
 
-            final Exchange exchange = getEndpoint().createExchange();
+            final Exchange exchange = createExchange(true);
             Message message = exchange.getIn();
             message.setBody(event);
 
-            try {
-                LOG.trace("Processing exchange [{}]...", exchange);
-                getAsyncProcessor().process(exchange, new AsyncCallback() {
-                    @Override
-                    public void done(boolean doneSync) {
-                        LOG.trace("Done processing exchange [{}]...", exchange);
+            LOG.trace("Processing exchange [{}]...", exchange);
+            getAsyncProcessor().process(exchange, new AsyncCallback() {
+                @Override
+                public void done(boolean doneSync) {
+                    if (exchange.getException() != null) {
+                        getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
                     }
-                });
-            } catch (Exception e) {
-                exchange.setException(e);
-            }
-            if (exchange.getException() != null) {
-                getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
-            }
+                }
+            });
         }
     }
 }
diff --git a/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerStatsConsumer.java b/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerStatsConsumer.java
index 268a823..4160f37 100644
--- a/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerStatsConsumer.java
+++ b/components/camel-docker/src/main/java/org/apache/camel/component/docker/consumer/DockerStatsConsumer.java
@@ -78,24 +78,19 @@ public class DockerStatsConsumer extends DefaultConsumer {
         public void onNext(Statistics statistics) {
             LOGGER.debug("Received Docker Statistics Event: {}", statistics);
 
-            final Exchange exchange = getEndpoint().createExchange();
+            final Exchange exchange = createExchange(true);
             Message message = exchange.getIn();
             message.setBody(statistics);
 
-            try {
-                LOGGER.trace("Processing exchange [{}]...", exchange);
-                getAsyncProcessor().process(exchange, new AsyncCallback() {
-                    @Override
-                    public void done(boolean doneSync) {
-                        LOGGER.trace("Done processing exchange [{}]...", exchange);
+            LOGGER.trace("Processing exchange [{}]...", exchange);
+            getAsyncProcessor().process(exchange, new AsyncCallback() {
+                @Override
+                public void done(boolean doneSync) {
+                    if (exchange.getException() != null) {
+                        getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
                     }
-                });
-            } catch (Exception e) {
-                exchange.setException(e);
-            }
-            if (exchange.getException() != null) {
-                getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
-            }
+                }
+            });
         }
     }
 }
diff --git a/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollConsumer.java b/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollConsumer.java
index 5d80590..36f8252 100644
--- a/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollConsumer.java
+++ b/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollConsumer.java
@@ -40,8 +40,6 @@ public abstract class DropboxScheduledPollConsumer extends ScheduledPollConsumer
     /**
      * Lifecycle method invoked when the consumer has created. Internally create or reuse a connection to the low level
      * dropbox client
-     * 
-     * @throws Exception
      */
     @Override
     protected void doStart() throws Exception {
@@ -57,8 +55,6 @@ public abstract class DropboxScheduledPollConsumer extends ScheduledPollConsumer
 
     /**
      * Lifecycle method invoked when the consumer has destroyed. Erase the reference to the dropbox low level client
-     * 
-     * @throws Exception
      */
     @Override
     protected void doStop() throws Exception {
diff --git a/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollGetConsumer.java b/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollGetConsumer.java
index 4097722..e624305 100644
--- a/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollGetConsumer.java
+++ b/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollGetConsumer.java
@@ -35,35 +35,33 @@ public class DropboxScheduledPollGetConsumer extends DropboxScheduledPollConsume
     /**
      * Poll from a dropbox remote path and put the result in the message exchange
      * 
-     * @return           number of messages polled
-     * @throws Exception
+     * @return number of messages polled
      */
     @Override
     protected int poll() throws Exception {
-        Exchange exchange = endpoint.createExchange();
-        DropboxFileDownloadResult result = new DropboxAPIFacade(configuration.getClient(), exchange)
-                .get(configuration.getRemotePath());
+        Exchange exchange = createExchange(false);
+        try {
+            DropboxFileDownloadResult result = new DropboxAPIFacade(configuration.getClient(), exchange)
+                    .get(configuration.getRemotePath());
 
-        Map<String, Object> map = result.getEntries();
-        if (map.size() == 1) {
-            for (Map.Entry<String, Object> entry : map.entrySet()) {
-                exchange.getIn().setHeader(DropboxResultHeader.DOWNLOADED_FILE.name(), entry.getKey());
-                exchange.getIn().setBody(entry.getValue());
-            }
-        } else {
-            StringBuilder pathsExtracted = new StringBuilder();
-            for (Map.Entry<String, Object> entry : map.entrySet()) {
-                pathsExtracted.append(entry.getKey()).append("\n");
+            Map<String, Object> map = result.getEntries();
+            if (map.size() == 1) {
+                for (Map.Entry<String, Object> entry : map.entrySet()) {
+                    exchange.getIn().setHeader(DropboxResultHeader.DOWNLOADED_FILE.name(), entry.getKey());
+                    exchange.getIn().setBody(entry.getValue());
+                }
+            } else {
+                StringBuilder pathsExtracted = new StringBuilder();
+                for (Map.Entry<String, Object> entry : map.entrySet()) {
+                    pathsExtracted.append(entry.getKey()).append("\n");
+                }
+                exchange.getIn().setHeader(DropboxResultHeader.DOWNLOADED_FILES.name(), pathsExtracted.toString());
+                exchange.getIn().setBody(map);
             }
-            exchange.getIn().setHeader(DropboxResultHeader.DOWNLOADED_FILES.name(), pathsExtracted.toString());
-            exchange.getIn().setBody(map);
-        }
 
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Downloaded: {}", result);
-        }
-
-        try {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Downloaded: {}", result);
+            }
             // send message to next processor in the route
             getProcessor().process(exchange);
             return 1; // number of messages polled
@@ -72,6 +70,7 @@ public class DropboxScheduledPollGetConsumer extends DropboxScheduledPollConsume
             if (exchange.getException() != null) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
             }
+            releaseExchange(exchange, false);
         }
     }
 }
diff --git a/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollSearchConsumer.java b/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollSearchConsumer.java
index 39c39e5..82b8017 100644
--- a/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollSearchConsumer.java
+++ b/components/camel-dropbox/src/main/java/org/apache/camel/component/dropbox/integration/consumer/DropboxScheduledPollSearchConsumer.java
@@ -35,29 +35,27 @@ public class DropboxScheduledPollSearchConsumer extends DropboxScheduledPollCons
     /**
      * Poll from a dropbox remote path and put the result in the message exchange
      * 
-     * @return           number of messages polled
-     * @throws Exception
+     * @return number of messages polled
      */
     @Override
     protected int poll() throws Exception {
-        Exchange exchange = endpoint.createExchange();
-        DropboxSearchResult result = new DropboxAPIFacade(configuration.getClient(), exchange)
-                .search(configuration.getRemotePath(), configuration.getQuery());
+        Exchange exchange = createExchange(false);
+        try {
+            DropboxSearchResult result = new DropboxAPIFacade(configuration.getClient(), exchange)
+                    .search(configuration.getRemotePath(), configuration.getQuery());
 
-        StringBuilder fileExtracted = new StringBuilder();
-        for (SearchMatch entry : result.getFound()) {
-            fileExtracted.append(entry.getMetadata().getName()).append("-").append(entry.getMetadata().getPathDisplay())
-                    .append("\n");
-        }
+            StringBuilder fileExtracted = new StringBuilder();
+            for (SearchMatch entry : result.getFound()) {
+                fileExtracted.append(entry.getMetadata().getName()).append("-").append(entry.getMetadata().getPathDisplay())
+                        .append("\n");
+            }
 
-        exchange.getIn().setHeader(DropboxResultHeader.FOUND_FILES.name(), fileExtracted.toString());
-        exchange.getIn().setBody(result.getFound());
+            exchange.getIn().setHeader(DropboxResultHeader.FOUND_FILES.name(), fileExtracted.toString());
+            exchange.getIn().setBody(result.getFound());
 
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Downloaded: {}", result);
-        }
-
-        try {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Downloaded: {}", result);
+            }
             // send message to next processor in the route
             getProcessor().process(exchange);
             return 1; // number of messages polled
@@ -66,6 +64,7 @@ public class DropboxScheduledPollSearchConsumer extends DropboxScheduledPollCons
             if (exchange.getException() != null) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
             }
+            releaseExchange(exchange, false);
         }
     }
 }
diff --git a/components/camel-ehcache/src/main/java/org/apache/camel/component/ehcache/EhcacheConsumer.java b/components/camel-ehcache/src/main/java/org/apache/camel/component/ehcache/EhcacheConsumer.java
index 7bf5f70..e784460 100644
--- a/components/camel-ehcache/src/main/java/org/apache/camel/component/ehcache/EhcacheConsumer.java
+++ b/components/camel-ehcache/src/main/java/org/apache/camel/component/ehcache/EhcacheConsumer.java
@@ -72,7 +72,7 @@ public class EhcacheConsumer extends DefaultConsumer implements CacheEventListen
     @Override
     public void onEvent(CacheEvent<?, ?> event) {
         if (isRunAllowed()) {
-            final Exchange exchange = getEndpoint().createExchange();
+            final Exchange exchange = createExchange(false);
             final Message message = exchange.getIn();
 
             message.setHeader(EhcacheConstants.KEY, event.getKey());
@@ -84,6 +84,8 @@ public class EhcacheConsumer extends DefaultConsumer implements CacheEventListen
                 getProcessor().process(exchange);
             } catch (Exception e) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, e);
+            } finally {
+                releaseExchange(exchange, false);
             }
         }
     }
diff --git a/components/camel-elsql/src/test/java/org/apache/camel/component/elsql/ElSqlConsumerDynamicParameterTest.java b/components/camel-elsql/src/test/java/org/apache/camel/component/elsql/ElSqlConsumerDynamicParameterTest.java
deleted file mode 100644
index 2f6623a..0000000
--- a/components/camel-elsql/src/test/java/org/apache/camel/component/elsql/ElSqlConsumerDynamicParameterTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.elsql;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.camel.BindToRegistry;
-import org.apache.camel.Exchange;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.test.junit5.CamelTestSupport;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
-import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
-import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-/**
- *
- */
-public class ElSqlConsumerDynamicParameterTest extends CamelTestSupport {
-
-    @BindToRegistry("dataSource")
-    private EmbeddedDatabase db = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.DERBY)
-            .addScript("sql/createAndPopulateDatabase.sql").build();
-    @BindToRegistry("myIdGenerator")
-    private MyIdGenerator idGenerator = new MyIdGenerator();
-
-    @Override
-    @AfterEach
-    public void tearDown() throws Exception {
-        super.tearDown();
-
-        db.shutdown();
-    }
-
-    @Test
-    void testDynamicConsume() throws Exception {
-        MockEndpoint mock = getMockEndpoint("mock:result");
-        mock.expectedMinimumMessageCount(3);
-
-        context.getRouteController().startRoute("foo");
-
-        assertMockEndpointsSatisfied();
-
-        List<Exchange> exchanges = mock.getReceivedExchanges();
-
-        assertEquals(1, exchanges.get(0).getIn().getBody(Map.class).get("ID"));
-        assertEquals("Camel", exchanges.get(0).getIn().getBody(Map.class).get("PROJECT"));
-        assertEquals(2, exchanges.get(1).getIn().getBody(Map.class).get("ID"));
-        assertEquals("AMQ", exchanges.get(1).getIn().getBody(Map.class).get("PROJECT"));
-        assertEquals(3, exchanges.get(2).getIn().getBody(Map.class).get("ID"));
-        assertEquals("Linux", exchanges.get(2).getIn().getBody(Map.class).get("PROJECT"));
-
-        // and the bean id should be > 1
-        assertTrue(idGenerator.getId() > 1, "Id counter should be > 1");
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() {
-        return new RouteBuilder() {
-            @Override
-            public void configure() {
-                from("elsql:projectsByIdBean:elsql/projects.elsql?dataSource=#dataSource&initialDelay=0&delay=50")
-                        .routeId("foo").noAutoStartup()
-                        .to("mock:result");
-            }
-        };
-    }
-
-    public static class MyIdGenerator {
-
-        private int id = 1;
-
-        public int nextId() {
-            // spring will call this twice, one for initializing query and 2nd
-            // for actual value
-            id++;
-            return id / 2;
-        }
-
-        public int getId() {
-            return id;
-        }
-    }
-}
diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConsumer.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConsumer.java
index c5e1b8c..e47c97e 100644
--- a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConsumer.java
+++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConsumer.java
@@ -35,7 +35,7 @@ public class EtcdStatsConsumer extends AbstractEtcdPollingConsumer {
         Object answer = endpoint.getStats(getClient());
 
         if (answer != null) {
-            Exchange exchange = endpoint.createExchange();
+            Exchange exchange = createExchange(true);
             exchange.getIn().setHeader(EtcdConstants.ETCD_NAMESPACE, "stats");
             exchange.getIn().setHeader(EtcdConstants.ETCD_PATH, endpoint.getPath());
             exchange.getIn().setBody(answer);
diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConsumer.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConsumer.java
index 6689ed6..2795129 100644
--- a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConsumer.java
+++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConsumer.java
@@ -93,7 +93,7 @@ public class EtcdWatchConsumer extends AbstractEtcdConsumer
             try {
                 EtcdKeysResponse response = promise.get();
 
-                exchange = endpoint.createExchange();
+                exchange = createExchange(false);
                 exchange.getIn().setHeader(EtcdConstants.ETCD_NAMESPACE, "watch");
                 exchange.getIn().setHeader(EtcdConstants.ETCD_PATH, response.node.key);
                 exchange.getIn().setBody(response);
@@ -127,6 +127,10 @@ public class EtcdWatchConsumer extends AbstractEtcdConsumer
             }
         }
 
+        if (exchange != null) {
+            releaseExchange(exchange, false);
+        }
+
         if (throwable != null) {
             handleException("Error processing etcd response", throwable);
         }
diff --git a/components/camel-facebook/src/main/java/org/apache/camel/component/facebook/FacebookConsumer.java b/components/camel-facebook/src/main/java/org/apache/camel/component/facebook/FacebookConsumer.java
index 343c4fe..f14f873 100644
--- a/components/camel-facebook/src/main/java/org/apache/camel/component/facebook/FacebookConsumer.java
+++ b/components/camel-facebook/src/main/java/org/apache/camel/component/facebook/FacebookConsumer.java
@@ -184,7 +184,7 @@ public class FacebookConsumer extends ScheduledPollConsumer {
     }
 
     private void processResult(Object result, String rawJSON) throws Exception {
-        Exchange exchange = endpoint.createExchange();
+        Exchange exchange = createExchange(false);
         exchange.getIn().setBody(result);
         if (rawJSON != null) {
             exchange.getIn().setHeader(FacebookConstants.RAW_JSON_HEADER, rawJSON);
@@ -197,6 +197,7 @@ public class FacebookConsumer extends ScheduledPollConsumer {
             if (exchange.getException() != null) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
             }
+            releaseExchange(exchange, false);
         }
     }
 
@@ -237,8 +238,7 @@ public class FacebookConsumer extends ScheduledPollConsumer {
         if (this.sinceTime == null) {
             // first poll, set this to (current time - initial poll delay)
             final Date startTime = new Date(
-                    currentMillis
-                                            - TimeUnit.MILLISECONDS.convert(getInitialDelay(), getTimeUnit()));
+                    currentMillis - TimeUnit.MILLISECONDS.convert(getInitialDelay(), getTimeUnit()));
             this.sinceTime = dateFormat.format(startTime);
         } else if (this.untilTime != null) {
             // use the last 'until' time
diff --git a/components/camel-file-watch/src/main/java/org/apache/camel/component/file/watch/FileWatchConsumer.java b/components/camel-file-watch/src/main/java/org/apache/camel/component/file/watch/FileWatchConsumer.java
index c1c8f77..e8b64ba 100644
--- a/components/camel-file-watch/src/main/java/org/apache/camel/component/file/watch/FileWatchConsumer.java
+++ b/components/camel-file-watch/src/main/java/org/apache/camel/component/file/watch/FileWatchConsumer.java
@@ -139,7 +139,7 @@ public class FileWatchConsumer extends DefaultConsumer {
     }
 
     private Exchange prepareExchange(FileEvent event) {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         File file = event.getEventPath().toFile();
         Message message = exchange.getIn();
         message.setBody(file);
diff --git a/components/camel-file/src/main/java/org/apache/camel/component/file/FileConsumer.java b/components/camel-file/src/main/java/org/apache/camel/component/file/FileConsumer.java
index 7b9ee71..50087fb 100644
--- a/components/camel-file/src/main/java/org/apache/camel/component/file/FileConsumer.java
+++ b/components/camel-file/src/main/java/org/apache/camel/component/file/FileConsumer.java
@@ -57,6 +57,15 @@ public class FileConsumer extends GenericFileConsumer<File> {
     }
 
     @Override
+    protected Exchange createExchange(GenericFile<File> file) {
+        Exchange exchange = createExchange(true);
+        if (file != null) {
+            file.bindToExchange(exchange, getEndpoint().isProbeContentType());
+        }
+        return exchange;
+    }
+
+    @Override
     protected boolean pollDirectory(String fileName, List<GenericFile<File>> fileList, int depth) {
         LOG.trace("pollDirectory from fileName: {}", fileName);
 
diff --git a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileConsumer.java b/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileConsumer.java
index 3e6a7b4..51b53a0 100644
--- a/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileConsumer.java
+++ b/components/camel-file/src/main/java/org/apache/camel/component/file/GenericFileConsumer.java
@@ -102,6 +102,11 @@ public abstract class GenericFileConsumer<T> extends ScheduledBatchPollingConsum
     }
 
     /**
+     * Creates the exchange from the polled file
+     */
+    protected abstract Exchange createExchange(GenericFile<T> file);
+
+    /**
      * Poll for files
      */
     @Override
@@ -164,7 +169,7 @@ public abstract class GenericFileConsumer<T> extends ScheduledBatchPollingConsum
         // use a linked list so we can dequeue the exchanges
         LinkedList<Exchange> exchanges = new LinkedList<>();
         for (GenericFile<T> file : files) {
-            Exchange exchange = endpoint.createExchange(file);
+            Exchange exchange = createExchange(file);
             endpoint.configureExchange(exchange);
             endpoint.configureMessage(file, exchange.getIn());
             exchanges.add(exchange);
@@ -267,6 +272,7 @@ public abstract class GenericFileConsumer<T> extends ScheduledBatchPollingConsum
             GenericFile<?> file = exchange.getProperty(FileComponent.FILE_EXCHANGE_FILE, GenericFile.class);
             String key = file.getAbsoluteFilePath();
             endpoint.getInProgressRepository().remove(key);
+            releaseExchange(exchange, true);
         }
     }
 
diff --git a/components/camel-flatpack/src/main/java/org/apache/camel/component/flatpack/FlatpackEndpoint.java b/components/camel-flatpack/src/main/java/org/apache/camel/component/flatpack/FlatpackEndpoint.java
index c9a9829..8b5d315 100644
--- a/components/camel-flatpack/src/main/java/org/apache/camel/component/flatpack/FlatpackEndpoint.java
+++ b/components/camel-flatpack/src/main/java/org/apache/camel/component/flatpack/FlatpackEndpoint.java
@@ -92,7 +92,9 @@ public class FlatpackEndpoint extends DefaultPollingEndpoint {
 
     @Override
     public Consumer createConsumer(Processor processor) throws Exception {
-        return new FlatpackConsumer(this, processor, loadBalancer);
+        FlatpackConsumer consumer = new FlatpackConsumer(this, processor, loadBalancer);
+        configureConsumer(consumer);
+        return consumer;
     }
 
     public void processDataSet(Exchange originalExchange, DataSet dataSet, int counter) throws Exception {
diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConsumer.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConsumer.java
index d428e24..83e2292 100644
--- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConsumer.java
+++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RemoteFileConsumer.java
@@ -59,6 +59,15 @@ public abstract class RemoteFileConsumer<T> extends GenericFileConsumer<T> {
     }
 
     @Override
+    protected Exchange createExchange(GenericFile<T> file) {
+        Exchange answer = createExchange(true);
+        if (file != null) {
+            file.bindToExchange(answer);
+        }
+        return answer;
+    }
+
+    @Override
     protected boolean prePollCheck() throws Exception {
         if (LOG.isTraceEnabled()) {
             LOG.trace("prePollCheck on {}", getEndpoint().getConfiguration().remoteServerInformation());
diff --git a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/RemoteFileIgnoreDoPollErrorTest.java b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/RemoteFileIgnoreDoPollErrorTest.java
index ade11ef..371aaac 100644
--- a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/RemoteFileIgnoreDoPollErrorTest.java
+++ b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/RemoteFileIgnoreDoPollErrorTest.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
@@ -27,6 +28,7 @@ import org.apache.camel.component.file.GenericFile;
 import org.apache.camel.component.file.GenericFileOperationFailedException;
 import org.apache.camel.component.file.GenericFileProcessStrategy;
 import org.apache.camel.component.file.GenericFileProducer;
+import org.apache.camel.impl.DefaultCamelContext;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -35,6 +37,9 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class RemoteFileIgnoreDoPollErrorTest {
+
+    private final CamelContext camelContext = new DefaultCamelContext();
+
     private final RemoteFileEndpoint<Object> remoteFileEndpoint = new RemoteFileEndpoint<Object>() {
         @Override
         protected RemoteFileConsumer<Object> buildConsumer(Processor processor) {
@@ -100,6 +105,9 @@ public class RemoteFileIgnoreDoPollErrorTest {
 
     private RemoteFileConsumer<Object> getRemoteFileConsumer(
             final String doPollResult, final boolean ignoreCannotRetrieveFile) {
+
+        remoteFileEndpoint.setCamelContext(camelContext);
+
         return new RemoteFileConsumer<Object>(remoteFileEndpoint, null, null, null) {
             @Override
             protected boolean doPollDirectory(
diff --git a/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitBranchConsumer.java b/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitBranchConsumer.java
index 49d9456..6dc075d 100644
--- a/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitBranchConsumer.java
+++ b/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitBranchConsumer.java
@@ -40,7 +40,7 @@ public class GitBranchConsumer extends AbstractGitConsumer {
         List<Ref> call = getGit().branchList().setListMode(ListMode.ALL).call();
         for (Ref ref : call) {
             if (!branchesConsumed.contains(ref.getName())) {
-                Exchange e = getEndpoint().createExchange();
+                Exchange e = createExchange(true);
                 e.getMessage().setBody(ref.getName());
                 e.getMessage().setHeader(GitConstants.GIT_BRANCH_LEAF, ref.getLeaf().getName());
                 e.getMessage().setHeader(GitConstants.GIT_BRANCH_OBJECT_ID, ref.getObjectId().getName());
diff --git a/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitCommitConsumer.java b/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitCommitConsumer.java
index 06e203b..122a85a 100644
--- a/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitCommitConsumer.java
+++ b/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitCommitConsumer.java
@@ -46,7 +46,7 @@ public class GitCommitConsumer extends AbstractGitConsumer {
         }
         for (RevCommit commit : commits) {
             if (!commitsConsumed.contains(commit.getId())) {
-                Exchange e = getEndpoint().createExchange();
+                Exchange e = createExchange(true);
                 e.getMessage().setBody(commit.getFullMessage());
                 e.getMessage().setHeader(GitConstants.GIT_COMMIT_ID, commit.getId());
                 e.getMessage().setHeader(GitConstants.GIT_COMMIT_AUTHOR_NAME, commit.getAuthorIdent().getName());
diff --git a/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitTagConsumer.java b/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitTagConsumer.java
index 31ea39a..7052764 100644
--- a/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitTagConsumer.java
+++ b/components/camel-git/src/main/java/org/apache/camel/component/git/consumer/GitTagConsumer.java
@@ -39,7 +39,7 @@ public class GitTagConsumer extends AbstractGitConsumer {
         List<Ref> call = getGit().tagList().call();
         for (Ref ref : call) {
             if (!tagsConsumed.contains(ref.getName())) {
-                Exchange e = getEndpoint().createExchange();
+                Exchange e = createExchange(true);
                 e.getMessage().setBody(ref.getName());
                 e.getMessage().setHeader(GitConstants.GIT_BRANCH_LEAF, ref.getLeaf().getName());
                 e.getMessage().setHeader(GitConstants.GIT_BRANCH_OBJECT_ID, ref.getObjectId().getName());
diff --git a/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/CommitConsumer.java b/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/CommitConsumer.java
index ac92e01..5a4bbf7 100644
--- a/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/CommitConsumer.java
+++ b/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/CommitConsumer.java
@@ -71,7 +71,7 @@ public class CommitConsumer extends AbstractGitHubConsumer {
 
         while (!newCommits.empty()) {
             RepositoryCommit newCommit = newCommits.pop();
-            Exchange e = getEndpoint().createExchange();
+            Exchange e = createExchange(true);
             e.getMessage().setHeader(GitHubConstants.GITHUB_COMMIT_AUTHOR, newCommit.getAuthor().getName());
             e.getMessage().setHeader(GitHubConstants.GITHUB_COMMIT_COMMITTER, newCommit.getCommitter().getName());
             e.getMessage().setHeader(GitHubConstants.GITHUB_COMMIT_SHA, newCommit.getSha());
diff --git a/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/EventsConsumer.java b/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/EventsConsumer.java
index 343fe45..a47e763 100644
--- a/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/EventsConsumer.java
+++ b/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/EventsConsumer.java
@@ -78,7 +78,7 @@ public class EventsConsumer extends AbstractGitHubConsumer {
             lastEventId = Long.parseLong(latestEvent.getId());
 
             for (Event event : newEvents) {
-                Exchange exchange = getEndpoint().createExchange();
+                Exchange exchange = createExchange(true);
                 exchange.getMessage().setBody(event.getType());
                 exchange.getMessage().setHeader(GitHubConstants.GITHUB_EVENT_PAYLOAD, event.getPayload());
                 getProcessor().process(exchange);
diff --git a/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/PullRequestCommentConsumer.java b/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/PullRequestCommentConsumer.java
index 7f2164b..fc4fa03 100644
--- a/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/PullRequestCommentConsumer.java
+++ b/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/PullRequestCommentConsumer.java
@@ -110,7 +110,7 @@ public class PullRequestCommentConsumer extends AbstractGitHubConsumer {
 
         while (!newComments.empty()) {
             Comment newComment = newComments.pop();
-            Exchange e = getEndpoint().createExchange();
+            Exchange e = createExchange(true);
             e.getIn().setBody(newComment);
 
             // Required by the producers.  Set it here for convenience.
diff --git a/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/PullRequestConsumer.java b/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/PullRequestConsumer.java
index 9d6b804..61d839c 100644
--- a/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/PullRequestConsumer.java
+++ b/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/PullRequestConsumer.java
@@ -76,7 +76,7 @@ public class PullRequestConsumer extends AbstractGitHubConsumer {
 
         while (!newPullRequests.empty()) {
             PullRequest newPullRequest = newPullRequests.pop();
-            Exchange e = getEndpoint().createExchange();
+            Exchange e = createExchange(true);
 
             e.getIn().setBody(newPullRequest);
 
diff --git a/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/TagConsumer.java b/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/TagConsumer.java
index 559cbba..91a7107 100644
--- a/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/TagConsumer.java
+++ b/components/camel-github/src/main/java/org/apache/camel/component/github/consumer/TagConsumer.java
@@ -56,7 +56,7 @@ public class TagConsumer extends AbstractGitHubConsumer {
 
         while (!newTags.empty()) {
             RepositoryTag newTag = newTags.pop();
-            Exchange e = getEndpoint().createExchange();
+            Exchange e = createExchange(true);
             e.getIn().setBody(newTag);
             getProcessor().process(e);
         }
diff --git a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConsumer.java b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConsumer.java
index 4d4f5e2..da70219 100644
--- a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConsumer.java
+++ b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamConsumer.java
@@ -16,17 +16,22 @@
  */
 package org.apache.camel.component.google.mail.stream;
 
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Queue;
 
+import com.google.api.client.util.Base64;
 import com.google.api.services.gmail.Gmail;
 import com.google.api.services.gmail.model.ListMessagesResponse;
 import com.google.api.services.gmail.model.Message;
+import com.google.api.services.gmail.model.MessagePart;
+import com.google.api.services.gmail.model.MessagePartHeader;
 import com.google.api.services.gmail.model.ModifyMessageRequest;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
 import org.apache.camel.ExtendedExchange;
 import org.apache.camel.Processor;
 import org.apache.camel.spi.Synchronization;
@@ -83,7 +88,7 @@ public class GoogleMailStreamConsumer extends ScheduledBatchPollingConsumer {
         if (c.getMessages() != null) {
             for (Message message : c.getMessages()) {
                 Message mess = getClient().users().messages().get("me", message.getId()).setFormat("FULL").execute();
-                Exchange exchange = getEndpoint().createExchange(getEndpoint().getExchangePattern(), mess);
+                Exchange exchange = createExchange(getEndpoint().getExchangePattern(), mess);
                 answer.add(exchange);
             }
         }
@@ -170,4 +175,40 @@ public class GoogleMailStreamConsumer extends ScheduledBatchPollingConsumer {
         }
     }
 
+    public Exchange createExchange(ExchangePattern pattern, com.google.api.services.gmail.model.Message mail) {
+        Exchange exchange = createExchange(true);
+        exchange.setPattern(pattern);
+        org.apache.camel.Message message = exchange.getIn();
+        exchange.getIn().setHeader(GoogleMailStreamConstants.MAIL_ID, mail.getId());
+        List<MessagePart> parts = mail.getPayload().getParts();
+        if (parts != null && parts.get(0).getBody().getData() != null) {
+            byte[] bodyBytes = Base64.decodeBase64(parts.get(0).getBody().getData().trim());
+            String body = new String(bodyBytes, StandardCharsets.UTF_8);
+            message.setBody(body);
+        }
+        configureHeaders(message, mail.getPayload().getHeaders());
+        return exchange;
+    }
+
+    private void configureHeaders(org.apache.camel.Message message, List<MessagePartHeader> headers) {
+        for (MessagePartHeader header : headers) {
+            String headerName = header.getName();
+            if ("SUBJECT".equalsIgnoreCase(headerName)) {
+                message.setHeader(GoogleMailStreamConstants.MAIL_SUBJECT, header.getValue());
+            }
+            if ("TO".equalsIgnoreCase(headerName)) {
+                message.setHeader(GoogleMailStreamConstants.MAIL_TO, header.getValue());
+            }
+            if ("FROM".equalsIgnoreCase(headerName)) {
+                message.setHeader(GoogleMailStreamConstants.MAIL_FROM, header.getValue());
+            }
+            if ("CC".equalsIgnoreCase(headerName)) {
+                message.setHeader(GoogleMailStreamConstants.MAIL_CC, header.getValue());
+            }
+            if ("BCC".equalsIgnoreCase(headerName)) {
+                message.setHeader(GoogleMailStreamConstants.MAIL_BCC, header.getValue());
+            }
+        }
+    }
+
 }
diff --git a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamEndpoint.java b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamEndpoint.java
index 8c47b31..947f69a2 100644
--- a/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamEndpoint.java
+++ b/components/camel-google-mail/src/main/java/org/apache/camel/component/google/mail/stream/GoogleMailStreamEndpoint.java
@@ -16,22 +16,15 @@
  */
 package org.apache.camel.component.google.mail.stream;
 
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
-import com.google.api.client.util.Base64;
 import com.google.api.services.gmail.Gmail;
 import com.google.api.services.gmail.model.Label;
 import com.google.api.services.gmail.model.ListLabelsResponse;
-import com.google.api.services.gmail.model.MessagePart;
-import com.google.api.services.gmail.model.MessagePartHeader;
 import com.google.common.base.Splitter;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.component.google.mail.GoogleMailClientFactory;
@@ -108,41 +101,6 @@ public class GoogleMailStreamEndpoint extends ScheduledPollEndpoint {
         return configuration;
     }
 
-    public Exchange createExchange(ExchangePattern pattern, com.google.api.services.gmail.model.Message mail) {
-        Exchange exchange = super.createExchange(pattern);
-        Message message = exchange.getIn();
-        exchange.getIn().setHeader(GoogleMailStreamConstants.MAIL_ID, mail.getId());
-        List<MessagePart> parts = mail.getPayload().getParts();
-        if (parts != null && parts.get(0).getBody().getData() != null) {
-            byte[] bodyBytes = Base64.decodeBase64(parts.get(0).getBody().getData().trim());
-            String body = new String(bodyBytes, StandardCharsets.UTF_8);
-            message.setBody(body);
-        }
-        setHeaders(message, mail.getPayload().getHeaders());
-        return exchange;
-    }
-
-    private void setHeaders(Message message, List<MessagePartHeader> headers) {
-        for (MessagePartHeader header : headers) {
-            String headerName = header.getName();
-            if ("SUBJECT".equalsIgnoreCase(headerName)) {
-                message.setHeader(GoogleMailStreamConstants.MAIL_SUBJECT, header.getValue());
-            }
-            if ("TO".equalsIgnoreCase(headerName)) {
-                message.setHeader(GoogleMailStreamConstants.MAIL_TO, header.getValue());
-            }
-            if ("FROM".equalsIgnoreCase(headerName)) {
-                message.setHeader(GoogleMailStreamConstants.MAIL_FROM, header.getValue());
-            }
-            if ("CC".equalsIgnoreCase(headerName)) {
-                message.setHeader(GoogleMailStreamConstants.MAIL_CC, header.getValue());
-            }
-            if ("BCC".equalsIgnoreCase(headerName)) {
-                message.setHeader(GoogleMailStreamConstants.MAIL_BCC, header.getValue());
-            }
-        }
-    }
-
     private List<String> splitLabels(String labels) {
         return Splitter.on(',').splitToList(labels);
     }
diff --git a/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/GooglePubsubConsumer.java b/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/GooglePubsubConsumer.java
index 360dadc..8adc5e1 100644
--- a/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/GooglePubsubConsumer.java
+++ b/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/GooglePubsubConsumer.java
@@ -40,7 +40,7 @@ import org.apache.camel.support.DefaultConsumer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-class GooglePubsubConsumer extends DefaultConsumer {
+public class GooglePubsubConsumer extends DefaultConsumer {
 
     private Logger localLog;
 
@@ -123,7 +123,7 @@ class GooglePubsubConsumer extends DefaultConsumer {
 
         private void asynchronousPull(String subscriptionName) {
             while (isRunAllowed() && !isSuspendingOrSuspended()) {
-                MessageReceiver messageReceiver = new CamelMessageReceiver(endpoint, processor);
+                MessageReceiver messageReceiver = new CamelMessageReceiver(GooglePubsubConsumer.this, endpoint, processor);
 
                 Subscriber subscriber = endpoint.getComponent().getSubscriber(subscriptionName, messageReceiver);
                 try {
@@ -152,7 +152,7 @@ class GooglePubsubConsumer extends DefaultConsumer {
                     PullResponse pullResponse = subscriber.pullCallable().call(pullRequest);
                     for (ReceivedMessage message : pullResponse.getReceivedMessagesList()) {
                         PubsubMessage pubsubMessage = message.getMessage();
-                        Exchange exchange = endpoint.createExchange();
+                        Exchange exchange = createExchange(true);
                         exchange.getIn().setBody(pubsubMessage.getData().toByteArray());
 
                         exchange.getIn().setHeader(GooglePubsubConstants.ACK_ID, message.getAckId());
@@ -171,7 +171,7 @@ class GooglePubsubConsumer extends DefaultConsumer {
                         try {
                             processor.process(exchange);
                         } catch (Exception e) {
-                            exchange.setException(e);
+                            getExceptionHandler().handleException(e);
                         }
                     }
                 } catch (IOException e) {
diff --git a/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/CamelMessageReceiver.java b/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/CamelMessageReceiver.java
index 0b441b0..d26d649 100644
--- a/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/CamelMessageReceiver.java
+++ b/components/camel-google-pubsub/src/main/java/org/apache/camel/component/google/pubsub/consumer/CamelMessageReceiver.java
@@ -24,6 +24,7 @@ import org.apache.camel.Exchange;
 import org.apache.camel.ExtendedExchange;
 import org.apache.camel.Processor;
 import org.apache.camel.component.google.pubsub.GooglePubsubConstants;
+import org.apache.camel.component.google.pubsub.GooglePubsubConsumer;
 import org.apache.camel.component.google.pubsub.GooglePubsubEndpoint;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -31,10 +32,12 @@ import org.slf4j.LoggerFactory;
 public class CamelMessageReceiver implements MessageReceiver {
 
     private final Logger localLog;
+    private final GooglePubsubConsumer consumer;
     private final GooglePubsubEndpoint endpoint;
     private final Processor processor;
 
-    public CamelMessageReceiver(GooglePubsubEndpoint endpoint, Processor processor) {
+    public CamelMessageReceiver(GooglePubsubConsumer consumer, GooglePubsubEndpoint endpoint, Processor processor) {
+        this.consumer = consumer;
         this.endpoint = endpoint;
         this.processor = processor;
         String loggerId = endpoint.getLoggerId();
@@ -50,7 +53,7 @@ public class CamelMessageReceiver implements MessageReceiver {
             localLog.trace("Received message ID : {}", pubsubMessage.getMessageId());
         }
 
-        Exchange exchange = endpoint.createExchange();
+        Exchange exchange = consumer.createExchange(true);
         exchange.getIn().setBody(pubsubMessage.getData().toByteArray());
 
         exchange.getIn().setHeader(GooglePubsubConstants.MESSAGE_ID, pubsubMessage.getMessageId());
@@ -67,7 +70,7 @@ public class CamelMessageReceiver implements MessageReceiver {
         try {
             processor.process(exchange);
         } catch (Exception e) {
-            exchange.setException(e);
+            consumer.getExceptionHandler().handleException(e);
         }
     }
 }
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java
index 5d382db..eb04b5d 100644
--- a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamConsumer.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.google.sheets.stream;
 import java.util.ArrayDeque;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.List;
 import java.util.Queue;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
@@ -29,6 +30,7 @@ import com.google.api.services.sheets.v4.model.Spreadsheet;
 import com.google.api.services.sheets.v4.model.ValueRange;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
+import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.support.ScheduledBatchPollingConsumer;
 import org.apache.camel.util.CastUtils;
@@ -89,12 +91,12 @@ public class GoogleSheetsStreamConsumer extends ScheduledBatchPollingConsumer {
                         if (getConfiguration().getMaxResults() > 0) {
                             valueRange.getValues().stream()
                                     .limit(getConfiguration().getMaxResults())
-                                    .map(values -> getEndpoint().createExchange(rangeIndex.get(), valueIndex.incrementAndGet(),
+                                    .map(values -> createExchange(rangeIndex.get(), valueIndex.incrementAndGet(),
                                             valueRange.getRange(), valueRange.getMajorDimension(), values))
                                     .forEach(answer::add);
                         } else {
                             valueRange.getValues().stream()
-                                    .map(values -> getEndpoint().createExchange(rangeIndex.get(), valueIndex.incrementAndGet(),
+                                    .map(values -> createExchange(rangeIndex.get(), valueIndex.incrementAndGet(),
                                             valueRange.getRange(), valueRange.getMajorDimension(), values))
                                     .forEach(answer::add);
                         }
@@ -112,7 +114,7 @@ public class GoogleSheetsStreamConsumer extends ScheduledBatchPollingConsumer {
                                             .collect(Collectors.toList()));
                                 }
                             })
-                            .map(valueRange -> getEndpoint().createExchange(rangeIndex.incrementAndGet(), valueRange))
+                            .map(valueRange -> createExchange(rangeIndex.incrementAndGet(), valueRange))
                             .forEach(answer::add);
                 }
             }
@@ -122,7 +124,7 @@ public class GoogleSheetsStreamConsumer extends ScheduledBatchPollingConsumer {
             request.setIncludeGridData(getConfiguration().isIncludeGridData());
 
             Spreadsheet spreadsheet = request.execute();
-            answer.add(getEndpoint().createExchange(spreadsheet));
+            answer.add(createExchange(spreadsheet));
         }
 
         return processBatch(CastUtils.cast(answer));
@@ -148,4 +150,42 @@ public class GoogleSheetsStreamConsumer extends ScheduledBatchPollingConsumer {
 
         return total;
     }
+
+    public Exchange createExchange(int rangeIndex, ValueRange valueRange) {
+        Exchange exchange = createExchange(true);
+        exchange.setPattern(getEndpoint().getExchangePattern());
+        Message message = exchange.getIn();
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID,
+                getEndpoint().getConfiguration().getSpreadsheetId());
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE, valueRange.getRange());
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE_INDEX, rangeIndex);
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.MAJOR_DIMENSION, valueRange.getMajorDimension());
+        message.setBody(valueRange);
+        return exchange;
+    }
+
+    public Exchange createExchange(int rangeIndex, int valueIndex, String range, String majorDimension, List<Object> values) {
+        Exchange exchange = createExchange(true);
+        exchange.setPattern(getEndpoint().getExchangePattern());
+        Message message = exchange.getIn();
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID,
+                getEndpoint().getConfiguration().getSpreadsheetId());
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE_INDEX, rangeIndex);
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.VALUE_INDEX, valueIndex);
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE, range);
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.MAJOR_DIMENSION, majorDimension);
+        message.setBody(values);
+        return exchange;
+    }
+
+    public Exchange createExchange(Spreadsheet spreadsheet) {
+        Exchange exchange = createExchange(true);
+        exchange.setPattern(getEndpoint().getExchangePattern());
+        Message message = exchange.getIn();
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID, spreadsheet.getSpreadsheetId());
+        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_URL, spreadsheet.getSpreadsheetUrl());
+        message.setBody(spreadsheet);
+        return exchange;
+    }
+
 }
diff --git a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java
index 18062f3..c17f148 100644
--- a/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java
+++ b/components/camel-google-sheets/src/main/java/org/apache/camel/component/google/sheets/stream/GoogleSheetsStreamEndpoint.java
@@ -16,15 +16,9 @@
  */
 package org.apache.camel.component.google.sheets.stream;
 
-import java.util.List;
-
 import com.google.api.services.sheets.v4.Sheets;
-import com.google.api.services.sheets.v4.model.Spreadsheet;
-import com.google.api.services.sheets.v4.model.ValueRange;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.component.google.sheets.GoogleSheetsClientFactory;
@@ -80,35 +74,4 @@ public class GoogleSheetsStreamEndpoint extends ScheduledPollEndpoint {
         return configuration;
     }
 
-    public Exchange createExchange(int rangeIndex, ValueRange valueRange) {
-        Exchange exchange = super.createExchange(getExchangePattern());
-        Message message = exchange.getIn();
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID, configuration.getSpreadsheetId());
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE, valueRange.getRange());
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE_INDEX, rangeIndex);
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.MAJOR_DIMENSION, valueRange.getMajorDimension());
-        message.setBody(valueRange);
-        return exchange;
-    }
-
-    public Exchange createExchange(int rangeIndex, int valueIndex, String range, String majorDimension, List<Object> values) {
-        Exchange exchange = super.createExchange(getExchangePattern());
-        Message message = exchange.getIn();
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID, configuration.getSpreadsheetId());
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE_INDEX, rangeIndex);
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.VALUE_INDEX, valueIndex);
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.RANGE, range);
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.MAJOR_DIMENSION, majorDimension);
-        message.setBody(values);
-        return exchange;
-    }
-
-    public Exchange createExchange(Spreadsheet spreadsheet) {
-        Exchange exchange = super.createExchange(getExchangePattern());
-        Message message = exchange.getIn();
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_ID, spreadsheet.getSpreadsheetId());
-        exchange.getIn().setHeader(GoogleSheetsStreamConstants.SPREADSHEET_URL, spreadsheet.getSpreadsheetUrl());
-        message.setBody(spreadsheet);
-        return exchange;
-    }
 }
diff --git a/components/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConsumer.java b/components/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConsumer.java
index 935b7e6..b8cede8 100644
--- a/components/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConsumer.java
+++ b/components/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageConsumer.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.component.google.storage;
 
+import java.io.ByteArrayOutputStream;
+import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Queue;
@@ -28,8 +30,11 @@ import com.google.cloud.storage.Storage;
 import com.google.cloud.storage.Storage.CopyRequest;
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
 import org.apache.camel.ExtendedExchange;
+import org.apache.camel.Message;
 import org.apache.camel.Processor;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.Synchronization;
 import org.apache.camel.support.ScheduledBatchPollingConsumer;
 import org.apache.camel.util.CastUtils;
@@ -73,7 +78,7 @@ public class GoogleCloudStorageConsumer extends ScheduledBatchPollingConsumer {
 
         String fileName = getConfiguration().getObjectName();
         String bucketName = getConfiguration().getBucketName();
-        Queue<Exchange> exchanges = new LinkedList<>();
+        Queue<Exchange> exchanges;
 
         if (fileName != null) {
             LOG.trace("Getting object in bucket [{}] with file name [{}]...", bucketName, fileName);
@@ -101,7 +106,7 @@ public class GoogleCloudStorageConsumer extends ScheduledBatchPollingConsumer {
 
     protected Queue<Exchange> createExchanges(Blob blob, String key) {
         Queue<Exchange> answer = new LinkedList<>();
-        Exchange exchange = getEndpoint().createExchange(blob, key);
+        Exchange exchange = createExchange(blob, key);
         answer.add(exchange);
         return answer;
     }
@@ -115,7 +120,7 @@ public class GoogleCloudStorageConsumer extends ScheduledBatchPollingConsumer {
         try {
             for (Blob blob : blobList) {
                 if (includeObject(blob)) {
-                    Exchange exchange = getEndpoint().createExchange(blob, blob.getBlobId().getName());
+                    Exchange exchange = createExchange(blob, blob.getBlobId().getName());
                     answer.add(exchange);
                 }
             }
@@ -248,4 +253,57 @@ public class GoogleCloudStorageConsumer extends ScheduledBatchPollingConsumer {
     public GoogleCloudStorageEndpoint getEndpoint() {
         return (GoogleCloudStorageEndpoint) super.getEndpoint();
     }
+
+    public Exchange createExchange(Blob blob, String key) {
+        return createExchange(getEndpoint().getExchangePattern(), blob, key);
+    }
+
+    public Exchange createExchange(ExchangePattern pattern, Blob blob, String key) {
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Getting object with key [{}] from bucket [{}]...", key, getConfiguration().getBucketName());
+            LOG.trace("Got object [{}]", blob);
+        }
+
+        Exchange exchange = createExchange(true);
+        exchange.setPattern(pattern);
+        Message message = exchange.getIn();
+
+        if (getConfiguration().isIncludeBody()) {
+            try {
+                ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                blob.downloadTo(baos);
+                message.setBody(baos.toByteArray());
+            } catch (Exception e) {
+                throw new RuntimeCamelException(e);
+            }
+        } else {
+            message.setBody(blob);
+        }
+
+        message.setHeader(GoogleCloudStorageConstants.OBJECT_NAME, key);
+        message.setHeader(GoogleCloudStorageConstants.BUCKET_NAME, getConfiguration().getBucketName());
+        //OTHER METADATA
+        message.setHeader(GoogleCloudStorageConstants.CACHE_CONTROL, blob.getCacheControl());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_COMPONENT_COUNT, blob.getComponentCount());
+        message.setHeader(GoogleCloudStorageConstants.CONTENT_DISPOSITION, blob.getContentDisposition());
+        message.setHeader(GoogleCloudStorageConstants.CONTENT_ENCODING, blob.getContentEncoding());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_CONTENT_LANGUAGE, blob.getContentLanguage());
+        message.setHeader(GoogleCloudStorageConstants.CONTENT_TYPE, blob.getContentType());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_CUSTOM_TIME, blob.getCustomTime());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_CRC32C_HEX, blob.getCrc32cToHexString());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_ETAG, blob.getEtag());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_GENERATION, blob.getGeneration());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_BLOB_ID, blob.getBlobId());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_KMS_KEY_NAME, blob.getKmsKeyName());
+        message.setHeader(GoogleCloudStorageConstants.CONTENT_MD5, blob.getMd5ToHexString());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_MEDIA_LINK, blob.getMediaLink());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_METAGENERATION, blob.getMetageneration());
+        message.setHeader(GoogleCloudStorageConstants.CONTENT_LENGTH, blob.getSize());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_STORAGE_CLASS, blob.getStorageClass());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_CREATE_TIME, blob.getCreateTime());
+        message.setHeader(GoogleCloudStorageConstants.METADATA_LAST_UPDATE, new Date(blob.getUpdateTime()));
+
+        return exchange;
+    }
+
 }
diff --git a/components/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpoint.java b/components/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpoint.java
index f3fe59a..79da387 100644
--- a/components/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpoint.java
+++ b/components/camel-google-storage/src/main/java/org/apache/camel/component/google/storage/GoogleCloudStorageEndpoint.java
@@ -16,10 +16,6 @@
  */
 package org.apache.camel.component.google.storage;
 
-import java.io.ByteArrayOutputStream;
-import java.util.Date;
-
-import com.google.cloud.storage.Blob;
 import com.google.cloud.storage.Bucket;
 import com.google.cloud.storage.BucketInfo;
 import com.google.cloud.storage.BucketInfo.Builder;
@@ -27,12 +23,8 @@ import com.google.cloud.storage.Storage;
 import com.google.cloud.storage.StorageClass;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
-import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.support.ScheduledPollEndpoint;
@@ -123,55 +115,4 @@ public class GoogleCloudStorageEndpoint extends ScheduledPollEndpoint {
         return storageClient;
     }
 
-    public Exchange createExchange(Blob blob, String key) {
-        return createExchange(getExchangePattern(), blob, key);
-    }
-
-    public Exchange createExchange(ExchangePattern pattern, Blob blob, String key) {
-        if (LOG.isTraceEnabled()) {
-            LOG.trace("Getting object with key [{}] from bucket [{}]...", key, getConfiguration().getBucketName());
-            LOG.trace("Got object [{}]", blob);
-        }
-
-        Exchange exchange = super.createExchange(pattern);
-        Message message = exchange.getIn();
-
-        if (configuration.isIncludeBody()) {
-            try {
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                blob.downloadTo(baos);
-                message.setBody(baos.toByteArray());
-            } catch (Exception e) {
-                throw new RuntimeCamelException(e);
-            }
-        } else {
-            message.setBody(blob);
-        }
-
-        message.setHeader(GoogleCloudStorageConstants.OBJECT_NAME, key);
-        message.setHeader(GoogleCloudStorageConstants.BUCKET_NAME, getConfiguration().getBucketName());
-        //OTHER METADATA        
-        message.setHeader(GoogleCloudStorageConstants.CACHE_CONTROL, blob.getCacheControl());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_COMPONENT_COUNT, blob.getComponentCount());
-        message.setHeader(GoogleCloudStorageConstants.CONTENT_DISPOSITION, blob.getContentDisposition());
-        message.setHeader(GoogleCloudStorageConstants.CONTENT_ENCODING, blob.getContentEncoding());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_CONTENT_LANGUAGE, blob.getContentLanguage());
-        message.setHeader(GoogleCloudStorageConstants.CONTENT_TYPE, blob.getContentType());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_CUSTOM_TIME, blob.getCustomTime());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_CRC32C_HEX, blob.getCrc32cToHexString());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_ETAG, blob.getEtag());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_GENERATION, blob.getGeneration());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_BLOB_ID, blob.getBlobId());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_KMS_KEY_NAME, blob.getKmsKeyName());
-        message.setHeader(GoogleCloudStorageConstants.CONTENT_MD5, blob.getMd5ToHexString());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_MEDIA_LINK, blob.getMediaLink());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_METAGENERATION, blob.getMetageneration());
-        message.setHeader(GoogleCloudStorageConstants.CONTENT_LENGTH, blob.getSize());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_STORAGE_CLASS, blob.getStorageClass());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_CREATE_TIME, blob.getCreateTime());
-        message.setHeader(GoogleCloudStorageConstants.METADATA_LAST_UPDATE, new Date(blob.getUpdateTime()));
-
-        return exchange;
-    }
-
 }
diff --git a/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConsumer.java b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConsumer.java
index 8bd0fc4..876c109 100644
--- a/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConsumer.java
+++ b/components/camel-gora/src/main/java/org/apache/camel/component/gora/GoraConsumer.java
@@ -76,7 +76,7 @@ public class GoraConsumer extends ScheduledPollConsumer {
 
     @Override
     protected int poll() throws Exception {
-        final Exchange exchange = this.getEndpoint().createExchange();
+        final Exchange exchange = createExchange(true);
 
         // compute time (approx) since last update
         if (firstRun) {
@@ -88,13 +88,7 @@ public class GoraConsumer extends ScheduledPollConsumer {
         //proceed with query
         final Result result = query.execute();
 
-        try {
-            getProcessor().process(exchange);
-        } finally {
-            if (exchange.getException() != null) {
-                getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
-            }
-        }
+        getProcessor().process(exchange);
 
         return Long.valueOf(result.getOffset()).intValue();
     }
diff --git a/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraConsumerTest.java b/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraConsumerTest.java
deleted file mode 100644
index 7acee3b..0000000
--- a/components/camel-gora/src/test/java/org/apache/camel/component/gora/GoraConsumerTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.gora;
-
-import java.lang.reflect.InvocationTargetException;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
-import org.apache.camel.Processor;
-import org.apache.gora.persistency.Persistent;
-import org.apache.gora.query.Query;
-import org.apache.gora.store.DataStore;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-import static org.mockito.Mockito.when;
-
-/**
- * GORA Consumer Tests
- */
-@ExtendWith(MockitoExtension.class)
-public class GoraConsumerTest extends GoraTestSupport {
-
-    /**
-     * Mock CamelExchange
-     */
-    @Mock
-    private Exchange mockCamelExchange;
-
-    /**
-     * Mock Gora Endpoint
-     */
-    @Mock
-    private GoraEndpoint mockGoraEndpoint;
-
-    /**
-     * Mock Gora Configuration
-     */
-    @Mock
-    private GoraConfiguration mockGoraConfiguration;
-
-    /**
-     * Mock Camel Message
-     */
-    @Mock
-    private Message mockCamelMessage;
-
-    /**
-     * Mock Gora DataStore
-     */
-    @Mock
-    private DataStore<Object, Persistent> mockDatastore;
-
-    /**
-     * Mock Processor
-     */
-    private Processor mockGoraProcessor;
-
-    /**
-     * Mock Query
-     */
-    @Mock
-    private Query<Object, Persistent> mockQuery;
-
-    @Test
-    public void consumerInstantiationWithMocksShouldSucceed()
-            throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
-        when(mockDatastore.newQuery()).thenReturn(mockQuery);
-        new GoraConsumer(mockGoraEndpoint, mockGoraProcessor, mockGoraConfiguration, mockDatastore);
-    }
-
-}
diff --git a/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/CamelEventHandler.java b/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/CamelEventHandler.java
index b5d8bcc..9b53f57 100644
--- a/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/CamelEventHandler.java
+++ b/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/CamelEventHandler.java
@@ -31,14 +31,16 @@ import org.slf4j.LoggerFactory;
 public class CamelEventHandler {
 
     protected final Logger log = LoggerFactory.getLogger(CamelEventHandler.class);
-    protected final GuavaEventBusEndpoint eventBusEndpoint;
+    protected final GuavaEventBusConsumer consumer;
+    protected final GuavaEventBusEndpoint endpoint;
     protected final AsyncProcessor processor;
 
-    public CamelEventHandler(GuavaEventBusEndpoint eventBusEndpoint, Processor processor) {
-        ObjectHelper.notNull(eventBusEndpoint, "eventBusEndpoint");
+    public CamelEventHandler(GuavaEventBusConsumer consumer, GuavaEventBusEndpoint endpoint, Processor processor) {
+        ObjectHelper.notNull(endpoint, "eventBusEndpoint");
         ObjectHelper.notNull(processor, "processor");
 
-        this.eventBusEndpoint = eventBusEndpoint;
+        this.consumer = consumer;
+        this.endpoint = endpoint;
         this.processor = AsyncProcessorConverterHelper.convert(processor);
     }
 
@@ -49,7 +51,7 @@ public class CamelEventHandler {
      */
     public void doEventReceived(Object event) {
         log.trace("Received event: {}", event);
-        final Exchange exchange = eventBusEndpoint.createExchange(event);
+        final Exchange exchange = createExchange(event);
         log.debug("Processing event: {}", event);
         // use async processor to support async routing engine
         processor.process(exchange, new AsyncCallback() {
@@ -60,4 +62,10 @@ public class CamelEventHandler {
         });
     }
 
+    public Exchange createExchange(Object event) {
+        Exchange exchange = consumer.createExchange(true);
+        exchange.getIn().setBody(event);
+        return exchange;
+    }
+
 }
diff --git a/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/FilteringCamelEventHandler.java b/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/FilteringCamelEventHandler.java
index 7b01d3b..c950d3f 100644
--- a/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/FilteringCamelEventHandler.java
+++ b/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/FilteringCamelEventHandler.java
@@ -27,8 +27,9 @@ public class FilteringCamelEventHandler extends CamelEventHandler {
 
     private final Class<?> eventClass;
 
-    public FilteringCamelEventHandler(GuavaEventBusEndpoint eventBusEndpoint, Processor processor, Class<?> eventClass) {
-        super(eventBusEndpoint, processor);
+    public FilteringCamelEventHandler(GuavaEventBusConsumer consumer, GuavaEventBusEndpoint endpoint, Processor processor,
+                                      Class<?> eventClass) {
+        super(consumer, endpoint, processor);
         this.eventClass = eventClass;
     }
 
diff --git a/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/GuavaEventBusConsumer.java b/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/GuavaEventBusConsumer.java
index 1740117..bdf9500 100644
--- a/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/GuavaEventBusConsumer.java
+++ b/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/GuavaEventBusConsumer.java
@@ -50,7 +50,7 @@ public class GuavaEventBusConsumer extends DefaultConsumer {
         if (listenerInterface != null) {
             this.eventHandler = createListenerInterfaceProxy(endpoint, processor, listenerInterface);
         } else {
-            this.eventHandler = new FilteringCamelEventHandler(endpoint, processor, eventClass);
+            this.eventHandler = new FilteringCamelEventHandler(this, endpoint, processor, eventClass);
         }
     }
 
@@ -72,7 +72,7 @@ public class GuavaEventBusConsumer extends DefaultConsumer {
             GuavaEventBusEndpoint endpoint, Processor processor, Class<?> listenerInterface) {
         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
         return Proxy.newProxyInstance(classLoader, new Class[] { listenerInterface },
-                new ListenerInterfaceHandler(endpoint, processor));
+                new ListenerInterfaceHandler(this, endpoint, processor));
     }
 
     private static final class ListenerInterfaceHandler implements InvocationHandler {
@@ -81,8 +81,8 @@ public class GuavaEventBusConsumer extends DefaultConsumer {
 
         private final CamelEventHandler delegateHandler;
 
-        private ListenerInterfaceHandler(GuavaEventBusEndpoint endpoint, Processor processor) {
-            this.delegateHandler = new CamelEventHandler(endpoint, processor);
+        private ListenerInterfaceHandler(GuavaEventBusConsumer consumer, GuavaEventBusEndpoint endpoint, Processor processor) {
+            this.delegateHandler = new CamelEventHandler(consumer, endpoint, processor);
         }
 
         @Override
diff --git a/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/GuavaEventBusEndpoint.java b/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/GuavaEventBusEndpoint.java
index d246eb6..83181b8 100644
--- a/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/GuavaEventBusEndpoint.java
+++ b/components/camel-guava-eventbus/src/main/java/org/apache/camel/component/guava/eventbus/GuavaEventBusEndpoint.java
@@ -20,7 +20,6 @@ import com.google.common.eventbus.EventBus;
 import org.apache.camel.Category;
 import org.apache.camel.Component;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
 import org.apache.camel.MultipleConsumersSupport;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
@@ -69,12 +68,6 @@ public class GuavaEventBusEndpoint extends DefaultEndpoint implements MultipleCo
         return true;
     }
 
-    public Exchange createExchange(Object event) {
-        Exchange exchange = createExchange();
-        exchange.getIn().setBody(event);
-        return exchange;
-    }
-
     public String getEventBusRef() {
         return eventBusRef;
     }
diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/instance/HazelcastInstanceConsumer.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/instance/HazelcastInstanceConsumer.java
index 3dc0450..6a9b392 100644
--- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/instance/HazelcastInstanceConsumer.java
+++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/instance/HazelcastInstanceConsumer.java
@@ -49,7 +49,7 @@ public class HazelcastInstanceConsumer extends DefaultConsumer {
         }
 
         private void sendExchange(MembershipEvent event, String action) {
-            Exchange exchange = getEndpoint().createExchange();
+            Exchange exchange = createExchange(false);
 
             HazelcastComponentHelper.setListenerHeaders(exchange, HazelcastConstants.INSTANCE_LISTENER, action);
 
@@ -71,6 +71,8 @@ public class HazelcastInstanceConsumer extends DefaultConsumer {
                         "Error processing exchange for Hazelcast consumer on your Hazelcast cluster.", exchange,
                         exchange.getException());
             }
+
+            releaseExchange(exchange, false);
         }
 
     }
diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/list/HazelcastListConsumer.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/list/HazelcastListConsumer.java
index f22a3bb..6178333 100644
--- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/list/HazelcastListConsumer.java
+++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/list/HazelcastListConsumer.java
@@ -42,9 +42,6 @@ public class HazelcastListConsumer extends HazelcastDefaultConsumer {
         queue = hazelcastInstance.getList(cacheName);
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStart()
-     */
     @Override
     protected void doStart() throws Exception {
         super.doStart();
@@ -52,9 +49,6 @@ public class HazelcastListConsumer extends HazelcastDefaultConsumer {
         listener = queue.addItemListener(new CamelItemListener(this, cacheName), true);
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStop()
-     */
     @Override
     protected void doStop() throws Exception {
         queue.removeItemListener(listener);
diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/listener/CamelListener.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/listener/CamelListener.java
index 9e330be..d7cdffa 100644
--- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/listener/CamelListener.java
+++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/listener/CamelListener.java
@@ -32,7 +32,7 @@ public class CamelListener {
     }
 
     protected void sendExchange(String operation, Object key, Object value) {
-        Exchange exchange = consumer.getEndpoint().createExchange();
+        Exchange exchange = consumer.createExchange(false);
 
         // set object to body
         exchange.getIn().setBody(value);
@@ -57,6 +57,8 @@ public class CamelListener {
                     exchange,
                     exchange.getException());
         }
+
+        consumer.releaseExchange(exchange, false);
     }
 
     public String getCacheName() {
diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/map/HazelcastMapConsumer.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/map/HazelcastMapConsumer.java
index 1e8fbff..2d16262 100644
--- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/map/HazelcastMapConsumer.java
+++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/map/HazelcastMapConsumer.java
@@ -37,9 +37,6 @@ public class HazelcastMapConsumer extends HazelcastDefaultConsumer {
         cache = hazelcastInstance.getMap(cacheName);
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStart()
-     */
     @Override
     protected void doStart() throws Exception {
         super.doStart();
@@ -47,9 +44,6 @@ public class HazelcastMapConsumer extends HazelcastDefaultConsumer {
         listener = cache.addEntryListener(new CamelMapListener(this, cacheName), true);
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStop()
-     */
     @Override
     protected void doStop() throws Exception {
         cache.removeEntryListener(listener);
diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/multimap/HazelcastMultimapConsumer.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/multimap/HazelcastMultimapConsumer.java
index 29c0d6a..a506fcb 100644
--- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/multimap/HazelcastMultimapConsumer.java
+++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/multimap/HazelcastMultimapConsumer.java
@@ -38,9 +38,6 @@ public class HazelcastMultimapConsumer extends HazelcastDefaultConsumer {
         cache = hazelcastInstance.getMultiMap(cacheName);
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStart()
-     */
     @Override
     protected void doStart() throws Exception {
         super.doStart();
@@ -48,9 +45,6 @@ public class HazelcastMultimapConsumer extends HazelcastDefaultConsumer {
         listener = cache.addEntryListener(new CamelEntryListener(this, cacheName), true);
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStop()
-     */
     @Override
     protected void doStop() throws Exception {
         cache.removeEntryListener(listener);
diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/queue/HazelcastQueueConsumer.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/queue/HazelcastQueueConsumer.java
index 7794bda..e177126 100644
--- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/queue/HazelcastQueueConsumer.java
+++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/queue/HazelcastQueueConsumer.java
@@ -86,12 +86,14 @@ public class HazelcastQueueConsumer extends HazelcastDefaultConsumer {
                         final Object body = queue.poll(config.getPollingTimeout(), TimeUnit.MILLISECONDS);
                         // CAMEL-16035 - If the polling timeout is exceeded with nothing to poll from the queue, the queue.poll() method return NULL
                         if (body != null) {
-                            Exchange exchange = getEndpoint().createExchange();
+                            Exchange exchange = createExchange(false);
                             exchange.getIn().setBody(body);
                             try {
                                 processor.process(exchange);
                             } catch (Exception e) {
                                 getExceptionHandler().handleException("Error during processing", exchange, e);
+                            } finally {
+                                releaseExchange(exchange, false);
                             }
                         }
                     } catch (InterruptedException e) {
diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/replicatedmap/HazelcastReplicatedmapConsumer.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/replicatedmap/HazelcastReplicatedmapConsumer.java
index 2a215fd..380def8 100644
--- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/replicatedmap/HazelcastReplicatedmapConsumer.java
+++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/replicatedmap/HazelcastReplicatedmapConsumer.java
@@ -38,9 +38,6 @@ public class HazelcastReplicatedmapConsumer extends HazelcastDefaultConsumer {
         cache = hazelcastInstance.getReplicatedMap(cacheName);
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStart()
-     */
     @Override
     protected void doStart() throws Exception {
         super.doStart();
@@ -48,9 +45,6 @@ public class HazelcastReplicatedmapConsumer extends HazelcastDefaultConsumer {
         listener = cache.addEntryListener(new CamelEntryListener(this, cacheName));
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStop()
-     */
     @Override
     protected void doStop() throws Exception {
         cache.removeEntryListener(listener);
diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
index a73aafe..c58db47 100644
--- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
+++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/seda/HazelcastSedaConsumer.java
@@ -76,7 +76,7 @@ public class HazelcastSedaConsumer extends DefaultConsumer implements Runnable {
         BaseQueue<?> queue = endpoint.getHazelcastInstance().getQueue(endpoint.getConfiguration().getQueueName());
 
         while (queue != null && isRunAllowed()) {
-            final Exchange exchange = this.getEndpoint().createExchange();
+            final Exchange exchange = createExchange(true);
 
             TransactionContext transactionCtx = null;
             try {
@@ -100,22 +100,25 @@ public class HazelcastSedaConsumer extends DefaultConsumer implements Runnable {
                         exchange.getIn().setBody(body);
                     }
                     try {
+                        final TransactionContext txc = transactionCtx;
                         // process using the asynchronous routing engine
                         processor.process(exchange, new AsyncCallback() {
                             public void done(boolean asyncDone) {
-                                // noop
+                                if (exchange.getException() != null) {
+                                    // Rollback
+                                    if (txc != null) {
+                                        txc.rollbackTransaction();
+                                    }
+                                    getExceptionHandler().handleException("Error processing exchange", exchange,
+                                            exchange.getException());
+                                }
+                                // It's OK, I commit
+                                if (exchange.getException() == null && txc != null) {
+                                    LOG.trace("Commit transaction: {}", txc.getTxnId());
+                                    txc.commitTransaction();
+                                }
                             }
                         });
-
-                        if (exchange.getException() != null) {
-                            // Rollback
-                            if (transactionCtx != null) {
-                                transactionCtx.rollbackTransaction();
-                            }
-                            getExceptionHandler().handleException("Error processing exchange", exchange,
-                                    exchange.getException());
-                        }
-
                     } catch (Exception e) {
                         LOG.error("Hzlq Exception caught: {}", e, e);
                         // Rollback
@@ -125,11 +128,6 @@ public class HazelcastSedaConsumer extends DefaultConsumer implements Runnable {
                         }
                     }
                 }
-                // It's OK, I commit
-                if (exchange.getException() == null && transactionCtx != null) {
-                    LOG.trace("Commit transaction: {}", transactionCtx.getTxnId());
-                    transactionCtx.commitTransaction();
-                }
             } catch (InterruptedException e) {
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("Hzlq Consumer Interrupted: {}", e, e);
diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/set/HazelcastSetConsumer.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/set/HazelcastSetConsumer.java
index 8a17cf9..4cf75e3 100644
--- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/set/HazelcastSetConsumer.java
+++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/set/HazelcastSetConsumer.java
@@ -40,9 +40,6 @@ public class HazelcastSetConsumer extends HazelcastDefaultConsumer {
         set = hazelcastInstance.getSet(cacheName);
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStart()
-     */
     @Override
     protected void doStart() throws Exception {
         super.doStart();
@@ -50,9 +47,6 @@ public class HazelcastSetConsumer extends HazelcastDefaultConsumer {
         listener = set.addItemListener(new CamelItemListener(this, cacheName), true);
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStop()
-     */
     @Override
     protected void doStop() throws Exception {
         set.removeItemListener(listener);
diff --git a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/topic/HazelcastTopicConsumer.java b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/topic/HazelcastTopicConsumer.java
index 1c816c6..67a1a2a 100644
--- a/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/topic/HazelcastTopicConsumer.java
+++ b/components/camel-hazelcast/src/main/java/org/apache/camel/component/hazelcast/topic/HazelcastTopicConsumer.java
@@ -25,9 +25,6 @@ import org.apache.camel.Processor;
 import org.apache.camel.component.hazelcast.HazelcastDefaultConsumer;
 import org.apache.camel.component.hazelcast.listener.CamelMessageListener;
 
-/**
- *
- */
 public class HazelcastTopicConsumer extends HazelcastDefaultConsumer {
 
     private ITopic<Object> topic;
@@ -44,9 +41,6 @@ public class HazelcastTopicConsumer extends HazelcastDefaultConsumer {
         }
     }
 
-    /**
-     * @see org.apache.camel.support.DefaultConsumer#doStart()
-     */
     @Override
     protected void doStart() throws Exception {
         super.doStart();
diff --git a/components/camel-hbase/src/main/java/org/apache/camel/component/hbase/HBaseConsumer.java b/components/camel-hbase/src/main/java/org/apache/camel/component/hbase/HBaseConsumer.java
index 59efd5a..d2c3867 100644
--- a/components/camel-hbase/src/main/java/org/apache/camel/component/hbase/HBaseConsumer.java
+++ b/components/camel-hbase/src/main/java/org/apache/camel/component/hbase/HBaseConsumer.java
@@ -29,6 +29,7 @@ import org.apache.camel.component.hbase.mapping.CellMappingStrategyFactory;
 import org.apache.camel.component.hbase.model.HBaseCell;
 import org.apache.camel.component.hbase.model.HBaseData;
 import org.apache.camel.component.hbase.model.HBaseRow;
+import org.apache.camel.support.DefaultExchange;
 import org.apache.camel.support.ScheduledBatchPollingConsumer;
 import org.apache.camel.util.CastUtils;
 import org.apache.camel.util.ObjectHelper;
@@ -94,7 +95,7 @@ public class HBaseConsumer extends ScheduledBatchPollingConsumer {
             ResultScanner scanner = table.getScanner(scan);
             int exchangeCount = 0;
             // The next three statements are used just to get a reference to the BodyCellMappingStrategy instance.
-            Exchange exchange = endpoint.createExchange();
+            Exchange exchange = new DefaultExchange(endpoint);
             exchange.getIn().setHeader(CellMappingStrategyFactory.STRATEGY, CellMappingStrategyFactory.BODY);
             CellMappingStrategy mappingStrategy = endpoint.getCellMappingStrategyFactory().getStrategy(exchange.getIn());
             for (Result result = scanner.next();
@@ -137,7 +138,7 @@ public class HBaseConsumer extends ScheduledBatchPollingConsumer {
                     }
 
                     data.getRows().add(resultRow);
-                    exchange = endpoint.createExchange();
+                    exchange = createExchange(true);
                     // Probably overkill but kept it here for consistency.
                     exchange.getIn().setHeader(CellMappingStrategyFactory.STRATEGY, CellMappingStrategyFactory.BODY);
                     mappingStrategy.applyScanResults(exchange.getIn(), data);
diff --git a/components/camel-hdfs/src/main/java/org/apache/camel/component/hdfs/HdfsConsumer.java b/components/camel-hdfs/src/main/java/org/apache/camel/component/hdfs/HdfsConsumer.java
index e25ac4e..7e197a4 100644
--- a/components/camel-hdfs/src/main/java/org/apache/camel/component/hdfs/HdfsConsumer.java
+++ b/components/camel-hdfs/src/main/java/org/apache/camel/component/hdfs/HdfsConsumer.java
@@ -179,36 +179,40 @@ public final class HdfsConsumer extends ScheduledPollConsumer {
     private void processHdfsInputStream(
             HdfsInputStream hdfsFile, Holder<Object> key, Holder<Object> value, AtomicInteger messageCount,
             AtomicInteger totalMessageCount) {
-        Exchange exchange = this.getEndpoint().createExchange();
-        Message message = exchange.getIn();
-        String fileName = StringUtils.substringAfterLast(hdfsFile.getActualPath(), "/");
-        message.setHeader(Exchange.FILE_NAME, fileName);
-        message.setHeader(Exchange.FILE_NAME_CONSUMED, fileName);
-        message.setHeader("CamelFileAbsolutePath", hdfsFile.getActualPath());
-        if (key.getValue() != null) {
-            message.setHeader(HdfsHeader.KEY.name(), key.getValue());
-        }
+        Exchange exchange = createExchange(false);
+        try {
+            Message message = exchange.getIn();
+            String fileName = StringUtils.substringAfterLast(hdfsFile.getActualPath(), "/");
+            message.setHeader(Exchange.FILE_NAME, fileName);
+            message.setHeader(Exchange.FILE_NAME_CONSUMED, fileName);
+            message.setHeader("CamelFileAbsolutePath", hdfsFile.getActualPath());
+            if (key.getValue() != null) {
+                message.setHeader(HdfsHeader.KEY.name(), key.getValue());
+            }
 
-        if (hdfsFile.getNumOfReadBytes() >= 0) {
-            message.setHeader(Exchange.FILE_LENGTH, hdfsFile.getNumOfReadBytes());
-        }
+            if (hdfsFile.getNumOfReadBytes() >= 0) {
+                message.setHeader(Exchange.FILE_LENGTH, hdfsFile.getNumOfReadBytes());
+            }
 
-        message.setBody(value.getValue());
+            message.setBody(value.getValue());
 
-        updateNewExchange(exchange, messageCount.get(), hdfsFile);
+            updateNewExchange(exchange, messageCount.get(), hdfsFile);
+
+            LOG.debug("Processing file [{}]", fileName);
 
-        LOG.debug("Processing file [{}]", fileName);
-        try {
             processor.process(exchange);
             totalMessageCount.incrementAndGet();
+
         } catch (Exception e) {
             exchange.setException(e);
+        } finally {
+            // in case of unhandled exceptions then let the exception handler handle them
+            if (exchange.getException() != null) {
+                getExceptionHandler().handleException(exchange.getException());
+            }
+            releaseExchange(exchange, false);
         }
 
-        // in case of unhandled exceptions then let the exception handler handle them
-        if (exchange.getException() != null) {
-            getExceptionHandler().handleException(exchange.getException());
-        }
     }
 
     private boolean normalFileIsDirectoryHasSuccessFile(FileStatus fileStatus, HdfsInfo info) {
diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
index 67a2907..12d42f8 100644
--- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
+++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/CamelServlet.java
@@ -256,7 +256,8 @@ public class CamelServlet extends HttpServlet implements HttpRegistryProvider {
         }
 
         // create exchange and set data on it
-        Exchange exchange = consumer.getEndpoint().createExchange(ExchangePattern.InOut);
+        Exchange exchange = consumer.createExchange(false);
+        exchange.setPattern(ExchangePattern.InOut);
 
         if (consumer.getEndpoint().isBridgeEndpoint()) {
             exchange.setProperty(Exchange.SKIP_GZIP_ENCODING, Boolean.TRUE);
@@ -362,6 +363,7 @@ public class CamelServlet extends HttpServlet implements HttpRegistryProvider {
             }
         } finally {
             consumer.doneUoW(exchange);
+            consumer.releaseExchange(exchange, false);
         }
     }
 
diff --git a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
index fdf99c8..b789c40 100644
--- a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
+++ b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java
@@ -173,17 +173,10 @@ public class HttpProducer extends DefaultProducer {
                 Object headerValue = entry.getValue();
 
                 if (headerValue != null) {
-                    if (headerValue instanceof String) {
-                        // optimise for string values
-                        String value = (String) headerValue;
-                        if (!strategy.applyFilterToCamelHeaders(key, value, exchange)) {
-                            httpRequest.addHeader(key, value);
-                        }
-                        continue;
-                    } else if (headerValue instanceof Long || headerValue instanceof Integer
-                            || headerValue instanceof Boolean) {
-                        // optimise for other common types
-                        String value = tc.convertTo(String.class, exchange, headerValue);
+                    if (headerValue instanceof String || headerValue instanceof Integer || headerValue instanceof Long
+                            || headerValue instanceof Boolean || headerValue instanceof Date) {
+                        // optimise for common types
+                        String value = headerValue.toString();
                         if (!strategy.applyFilterToCamelHeaders(key, value, exchange)) {
                             httpRequest.addHeader(key, value);
                         }
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/Constants.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/Constants.java
index 926e01a..65d2b31 100644
--- a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/Constants.java
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/Constants.java
@@ -22,4 +22,9 @@ public interface Constants {
     String PARAM_PROTOCOL_OPTIONS = "protocolOptions";
 
     String PARAM_CONNECTION_OPTIONS = "connectionOptions";
+
+    String IEC60870_VALUE = "CamelIec60870Value";
+    String IEC60870_TIMESTAMP = "CamelIec60870Timestamp";
+    String IEC60870_QUALITY = "CamelIec60870Quality";
+    String IEC60870_OVERFLOW = "CamelIec60870Overflow";
 }
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConsumer.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConsumer.java
index 43a80d2..c1bf5e3 100644
--- a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConsumer.java
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConsumer.java
@@ -16,22 +16,16 @@
  */
 package org.apache.camel.component.iec60870.client;
 
-import java.time.Instant;
-
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
+import org.apache.camel.component.iec60870.Constants;
 import org.apache.camel.component.iec60870.ObjectAddress;
 import org.apache.camel.support.DefaultConsumer;
-import org.apache.camel.support.DefaultMessage;
 import org.eclipse.neoscada.protocol.iec60870.asdu.types.Value;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class ClientConsumer extends DefaultConsumer {
 
-    private static final Logger LOG = LoggerFactory.getLogger(ClientConsumer.class);
-
     private final ClientConnection connection;
     private final ClientEndpoint endpoint;
 
@@ -56,24 +50,20 @@ public class ClientConsumer extends DefaultConsumer {
     private void updateValue(final ObjectAddress address, final Value<?> value) {
         // Note: we hold the sync lock for the connection
         try {
-            final Exchange exchange = getEndpoint().createExchange();
-            exchange.setIn(mapMessage(value));
+            Exchange exchange = createExchange(true);
+            configureMessage(exchange.getIn(), value);
             getProcessor().process(exchange);
-        } catch (final Exception e) {
-            LOG.debug("Failed to process message", e);
+        } catch (Exception e) {
+            getExceptionHandler().handleException(e);
         }
     }
 
-    private Message mapMessage(final Value<?> value) {
-        final DefaultMessage message = new DefaultMessage(this.endpoint.getCamelContext());
-
+    private void configureMessage(Message message, final Value<?> value) {
         message.setBody(value);
 
-        message.setHeader("value", value.getValue());
-        message.setHeader("timestamp", Instant.ofEpochMilli(value.getTimestamp()));
-        message.setHeader("quality", value.getQualityInformation());
-        message.setHeader("overflow", value.isOverflow());
-
-        return message;
+        message.setHeader(Constants.IEC60870_VALUE, value.getValue());
+        message.setHeader(Constants.IEC60870_TIMESTAMP, value.getTimestamp());
+        message.setHeader(Constants.IEC60870_QUALITY, value.getQualityInformation());
+        message.setHeader(Constants.IEC60870_OVERFLOW, value.isOverflow());
     }
 }
diff --git a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/events/IgniteEventsConsumer.java b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/events/IgniteEventsConsumer.java
index 42b3e34..9b682f0 100644
--- a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/events/IgniteEventsConsumer.java
+++ b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/events/IgniteEventsConsumer.java
@@ -21,7 +21,6 @@ import java.util.List;
 
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.support.DefaultConsumer;
@@ -47,7 +46,7 @@ public class IgniteEventsConsumer extends DefaultConsumer {
 
         @Override
         public boolean apply(Event event) {
-            Exchange exchange = endpoint.createExchange(ExchangePattern.InOnly);
+            Exchange exchange = createExchange(true);
             Message in = exchange.getIn();
             in.setBody(event);
             try {
diff --git a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/messaging/IgniteMessagingConsumer.java b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/messaging/IgniteMessagingConsumer.java
index d9b8fb1..fc21167 100644
--- a/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/messaging/IgniteMessagingConsumer.java
+++ b/components/camel-ignite/src/main/java/org/apache/camel/component/ignite/messaging/IgniteMessagingConsumer.java
@@ -19,7 +19,6 @@ package org.apache.camel.component.ignite.messaging;
 import java.util.UUID;
 
 import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.component.ignite.IgniteConstants;
@@ -44,12 +43,12 @@ public class IgniteMessagingConsumer extends DefaultConsumer {
 
         @Override
         public boolean apply(UUID uuid, Object payload) {
-            Exchange exchange = endpoint.createExchange(ExchangePattern.InOnly);
-            Message in = exchange.getIn();
-            in.setBody(payload);
-            in.setHeader(IgniteConstants.IGNITE_MESSAGING_TOPIC, endpoint.getTopic());
-            in.setHeader(IgniteConstants.IGNITE_MESSAGING_UUID, uuid);
+            Exchange exchange = createExchange(true);
             try {
+                Message in = exchange.getIn();
+                in.setBody(payload);
+                in.setHeader(IgniteConstants.IGNITE_MESSAGING_TOPIC, endpoint.getTopic());
+                in.setHeader(IgniteConstants.IGNITE_MESSAGING_UUID, uuid);
                 if (LOG.isTraceEnabled()) {
                     LOG.trace("Processing Ignite message for subscription {} with payload {}.", uuid, payload);
                 }
diff --git a/components/camel-infinispan/camel-infinispan-common/src/main/java/org/apache/camel/component/infinispan/InfinispanConsumer.java b/components/camel-infinispan/camel-infinispan-common/src/main/java/org/apache/camel/component/infinispan/InfinispanConsumer.java
index 9c09afb..12b855e 100644
--- a/components/camel-infinispan/camel-infinispan-common/src/main/java/org/apache/camel/component/infinispan/InfinispanConsumer.java
+++ b/components/camel-infinispan/camel-infinispan-common/src/main/java/org/apache/camel/component/infinispan/InfinispanConsumer.java
@@ -45,24 +45,26 @@ public abstract class InfinispanConsumer<
 
     @Override
     public void processEvent(String eventType, String cacheName, Object key, Object eventData, Consumer<Exchange> consumer) {
-        Exchange exchange = getEndpoint().createExchange();
-        exchange.getMessage().setHeader(InfinispanConstants.EVENT_TYPE, eventType);
-        exchange.getMessage().setHeader(InfinispanConstants.CACHE_NAME, cacheName);
+        Exchange exchange = createExchange(false);
+        try {
+            exchange.getMessage().setHeader(InfinispanConstants.EVENT_TYPE, eventType);
+            exchange.getMessage().setHeader(InfinispanConstants.CACHE_NAME, cacheName);
 
-        if (key != null) {
-            exchange.getMessage().setHeader(InfinispanConstants.KEY, key);
-        }
-        if (eventData != null) {
-            exchange.getMessage().setHeader(InfinispanConstants.EVENT_DATA, eventData);
-        }
-        if (consumer != null) {
-            consumer.accept(exchange);
-        }
+            if (key != null) {
+                exchange.getMessage().setHeader(InfinispanConstants.KEY, key);
+            }
+            if (eventData != null) {
+                exchange.getMessage().setHeader(InfinispanConstants.EVENT_DATA, eventData);
+            }
+            if (consumer != null) {
+                consumer.accept(exchange);
+            }
 
-        try {
             getProcessor().process(exchange);
         } catch (Exception e) {
             getExceptionHandler().handleException(e);
+        } finally {
+            releaseExchange(exchange, false);
         }
     }
 
diff --git a/components/camel-irc/src/main/java/org/apache/camel/component/irc/IrcConsumer.java b/components/camel-irc/src/main/java/org/apache/camel/component/irc/IrcConsumer.java
index f1141ca..b6cf0b3 100644
--- a/components/camel-irc/src/main/java/org/apache/camel/component/irc/IrcConsumer.java
+++ b/components/camel-irc/src/main/java/org/apache/camel/component/irc/IrcConsumer.java
@@ -78,6 +78,78 @@ public class IrcConsumer extends DefaultConsumer {
         endpoint.joinChannels();
     }
 
+    private Exchange createOnPrivmsgExchange(String target, IRCUser user, String msg) {
+        Exchange exchange = createExchange(true);
+        exchange.setProperty(Exchange.BINDING, endpoint.getBinding());
+        IrcMessage im = new IrcMessage(endpoint.getCamelContext(), "PRIVMSG", target, user, msg);
+        exchange.setIn(im);
+        return exchange;
+    }
+
+    private Exchange createOnNickExchange(IRCUser user, String newNick) {
+        Exchange exchange = createExchange(true);
+        exchange.setProperty(Exchange.BINDING, endpoint.getBinding());
+        IrcMessage im = new IrcMessage(endpoint.getCamelContext(), "NICK", user, newNick);
+        exchange.setIn(im);
+        return exchange;
+    }
+
+    private Exchange createOnQuitExchange(IRCUser user, String msg) {
+        Exchange exchange = createExchange(true);
+        exchange.setProperty(Exchange.BINDING, endpoint.getBinding());
+        IrcMessage im = new IrcMessage(endpoint.getCamelContext(), "QUIT", user, msg);
+        exchange.setIn(im);
+        return exchange;
+    }
+
+    private Exchange createOnJoinExchange(String channel, IRCUser user) {
+        Exchange exchange = createExchange(true);
+        exchange.setProperty(Exchange.BINDING, endpoint.getBinding());
+        IrcMessage im = new IrcMessage(endpoint.getCamelContext(), "JOIN", channel, user);
+        exchange.setIn(im);
+        return exchange;
+    }
+
+    private Exchange createOnKickExchange(String channel, IRCUser user, String whoWasKickedNick, String msg) {
+        Exchange exchange = createExchange(true);
+        exchange.setProperty(Exchange.BINDING, endpoint.getBinding());
+        IrcMessage im = new IrcMessage(endpoint.getCamelContext(), "KICK", channel, user, whoWasKickedNick, msg);
+        exchange.setIn(im);
+        return exchange;
+    }
+
+    private Exchange createOnModeExchange(String channel, IRCUser user, IRCModeParser modeParser) {
+        Exchange exchange = createExchange(true);
+        exchange.setProperty(Exchange.BINDING, endpoint.getBinding());
+        IrcMessage im = new IrcMessage(endpoint.getCamelContext(), "MODE", channel, user, modeParser.getLine());
+        exchange.setIn(im);
+        return exchange;
+    }
+
+    private Exchange createOnPartExchange(String channel, IRCUser user, String msg) {
+        Exchange exchange = createExchange(true);
+        exchange.setProperty(Exchange.BINDING, endpoint.getBinding());
+        IrcMessage im = new IrcMessage(endpoint.getCamelContext(), "PART", channel, user, msg);
+        exchange.setIn(im);
+        return exchange;
+    }
+
+    private Exchange createOnReplyExchange(int num, String value, String msg) {
+        Exchange exchange = createExchange(true);
+        exchange.setProperty(Exchange.BINDING, endpoint.getBinding());
+        IrcMessage im = new IrcMessage(endpoint.getCamelContext(), "REPLY", num, value, msg);
+        exchange.setIn(im);
+        return exchange;
+    }
+
+    private Exchange createOnTopicExchange(String channel, IRCUser user, String topic) {
+        Exchange exchange = createExchange(true);
+        exchange.setProperty(Exchange.BINDING, endpoint.getBinding());
+        IrcMessage im = new IrcMessage(endpoint.getCamelContext(), "TOPIC", channel, user, topic);
+        exchange.setIn(im);
+        return exchange;
+    }
+
     public IRCConnection getConnection() {
         return connection;
     }
@@ -95,7 +167,7 @@ public class IrcConsumer extends DefaultConsumer {
         @Override
         public void onNick(IRCUser user, String newNick) {
             if (configuration.isOnNick()) {
-                Exchange exchange = endpoint.createOnNickExchange(user, newNick);
+                Exchange exchange = createOnNickExchange(user, newNick);
                 try {
                     getProcessor().process(exchange);
                 } catch (Exception e) {
@@ -107,7 +179,7 @@ public class IrcConsumer extends DefaultConsumer {
         @Override
         public void onQuit(IRCUser user, String msg) {
             if (configuration.isOnQuit()) {
-                Exchange exchange = endpoint.createOnQuitExchange(user, msg);
+                Exchange exchange = createOnQuitExchange(user, msg);
                 try {
                     getProcessor().process(exchange);
                 } catch (Exception e) {
@@ -119,7 +191,7 @@ public class IrcConsumer extends DefaultConsumer {
         @Override
         public void onJoin(String channel, IRCUser user) {
             if (configuration.isOnJoin()) {
-                Exchange exchange = endpoint.createOnJoinExchange(channel, user);
+                Exchange exchange = createOnJoinExchange(channel, user);
                 try {
                     getProcessor().process(exchange);
                 } catch (Exception e) {
@@ -137,7 +209,7 @@ public class IrcConsumer extends DefaultConsumer {
             }
 
             if (configuration.isOnKick()) {
-                Exchange exchange = endpoint.createOnKickExchange(channel, user, passiveNick, msg);
+                Exchange exchange = createOnKickExchange(channel, user, passiveNick, msg);
                 try {
                     getProcessor().process(exchange);
                 } catch (Exception e) {
@@ -149,7 +221,7 @@ public class IrcConsumer extends DefaultConsumer {
         @Override
         public void onMode(String channel, IRCUser user, IRCModeParser modeParser) {
             if (configuration.isOnMode()) {
-                Exchange exchange = endpoint.createOnModeExchange(channel, user, modeParser);
+                Exchange exchange = createOnModeExchange(channel, user, modeParser);
                 try {
                     getProcessor().process(exchange);
                 } catch (Exception e) {
@@ -161,7 +233,7 @@ public class IrcConsumer extends DefaultConsumer {
         @Override
         public void onPart(String channel, IRCUser user, String msg) {
             if (configuration.isOnPart()) {
-                Exchange exchange = endpoint.createOnPartExchange(channel, user, msg);
+                Exchange exchange = createOnPartExchange(channel, user, msg);
                 try {
                     getProcessor().process(exchange);
                 } catch (Exception e) {
@@ -173,7 +245,7 @@ public class IrcConsumer extends DefaultConsumer {
         @Override
         public void onReply(int num, String value, String msg) {
             if (configuration.isOnReply()) {
-                Exchange exchange = endpoint.createOnReplyExchange(num, value, msg);
+                Exchange exchange = createOnReplyExchange(num, value, msg);
                 try {
                     getProcessor().process(exchange);
                 } catch (Exception e) {
@@ -185,7 +257,7 @@ public class IrcConsumer extends DefaultConsumer {
         @Override
         public void onTopic(String channel, IRCUser user, String topic) {
             if (configuration.isOnTopic()) {
-                Exchange exchange = endpoint.createOnTopicExchange(channel, user, topic);
+                Exchange exchange = createOnTopicExchange(channel, user, topic);
                 try {
                     getProcessor().process(exchange);
                 } catch (Exception e) {
@@ -197,7 +269,7 @@ public class IrcConsumer extends DefaultConsumer {
         @Override
         public void onPrivmsg(String target, IRCUser user, String msg) {
             if (configuration.isOnPrivmsg()) {
-                Exchange exchange = endpoint.createOnPrivmsgExchange(target, user, msg);
+                Exchange exchange = createOnPrivmsgExchange(target, user, msg);
                 try {
                     getProcessor().process(exchange);
                 } catch (Exception e) {
diff --git a/components/camel-irc/src/main/java/org/apache/camel/component/irc/IrcEndpoint.java b/components/camel-irc/src/main/java/org/apache/camel/component/irc/IrcEndpoint.java
index 32f1f00..4a81b56 100644
--- a/components/camel-irc/src/main/java/org/apache/camel/component/irc/IrcEndpoint.java
+++ b/components/camel-irc/src/main/java/org/apache/camel/component/irc/IrcEndpoint.java
@@ -17,8 +17,6 @@
 package org.apache.camel.component.irc;
 
 import org.apache.camel.Category;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
 import org.apache.camel.Processor;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -27,16 +25,13 @@ import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.UnsafeUriCharactersEncoder;
 import org.schwering.irc.lib.IRCConnection;
 import org.schwering.irc.lib.IRCConstants;
-import org.schwering.irc.lib.IRCModeParser;
-import org.schwering.irc.lib.IRCUser;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * Send and receive messages to/from and IRC chat.
  */
-@UriEndpoint(
-             firstVersion = "1.1.0",
+@UriEndpoint(firstVersion = "1.1.0",
              scheme = "irc",
              title = "IRC",
              syntax = "irc:hostname:port",
@@ -58,76 +53,6 @@ public class IrcEndpoint extends DefaultEndpoint {
     }
 
     @Override
-    public Exchange createExchange(ExchangePattern pattern) {
-        Exchange exchange = super.createExchange(pattern);
-        exchange.setProperty(Exchange.BINDING, getBinding());
-        return exchange;
-    }
-
-    public Exchange createOnPrivmsgExchange(String target, IRCUser user, String msg) {
-        Exchange exchange = createExchange();
-        IrcMessage im = new IrcMessage(getCamelContext(), "PRIVMSG", target, user, msg);
-        exchange.setIn(im);
-        return exchange;
-    }
-
-    public Exchange createOnNickExchange(IRCUser user, String newNick) {
-        Exchange exchange = createExchange();
-        IrcMessage im = new IrcMessage(getCamelContext(), "NICK", user, newNick);
-        exchange.setIn(im);
-        return exchange;
-    }
-
-    public Exchange createOnQuitExchange(IRCUser user, String msg) {
-        Exchange exchange = createExchange();
-        IrcMessage im = new IrcMessage(getCamelContext(), "QUIT", user, msg);
-        exchange.setIn(im);
-        return exchange;
-    }
-
-    public Exchange createOnJoinExchange(String channel, IRCUser user) {
-        Exchange exchange = createExchange();
-        IrcMessage im = new IrcMessage(getCamelContext(), "JOIN", channel, user);
-        exchange.setIn(im);
-        return exchange;
-    }
-
-    public Exchange createOnKickExchange(String channel, IRCUser user, String whoWasKickedNick, String msg) {
-        Exchange exchange = createExchange();
-        IrcMessage im = new IrcMessage(getCamelContext(), "KICK", channel, user, whoWasKickedNick, msg);
-        exchange.setIn(im);
-        return exchange;
-    }
-
-    public Exchange createOnModeExchange(String channel, IRCUser user, IRCModeParser modeParser) {
-        Exchange exchange = createExchange();
-        IrcMessage im = new IrcMessage(getCamelContext(), "MODE", channel, user, modeParser.getLine());
-        exchange.setIn(im);
-        return exchange;
-    }
-
-    public Exchange createOnPartExchange(String channel, IRCUser user, String msg) {
-        Exchange exchange = createExchange();
-        IrcMessage im = new IrcMessage(getCamelContext(), "PART", channel, user, msg);
-        exchange.setIn(im);
-        return exchange;
-    }
-
-    public Exchange createOnReplyExchange(int num, String value, String msg) {
-        Exchange exchange = createExchange();
-        IrcMessage im = new IrcMessage(getCamelContext(), "REPLY", num, value, msg);
-        exchange.setIn(im);
-        return exchange;
-    }
-
-    public Exchange createOnTopicExchange(String channel, IRCUser user, String topic) {
-        Exchange exchange = createExchange();
-        IrcMessage im = new IrcMessage(getCamelContext(), "TOPIC", channel, user, topic);
-        exchange.setIn(im);
-        return exchange;
-    }
-
-    @Override
     public IrcProducer createProducer() throws Exception {
         return new IrcProducer(this);
     }
diff --git a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcConsumerTest.java b/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcConsumerTest.java
index cfcb1da..13851b7 100644
--- a/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcConsumerTest.java
+++ b/components/camel-irc/src/test/java/org/apache/camel/component/irc/IrcConsumerTest.java
@@ -19,18 +19,23 @@ package org.apache.camel.component.irc;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Processor;
+import org.apache.camel.spi.ExchangeFactory;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.schwering.irc.lib.IRCConnection;
 import org.schwering.irc.lib.IRCEventAdapter;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 public class IrcConsumerTest {
 
+    private ExtendedCamelContext context;
+    private ExchangeFactory exchangeFactory;
     private IRCConnection connection;
     private Processor processor;
     private IrcEndpoint endpoint;
@@ -45,6 +50,8 @@ public class IrcConsumerTest {
         processor = mock(Processor.class);
         configuration = mock(IrcConfiguration.class);
         listener = mock(IRCEventAdapter.class);
+        context = mock(ExtendedCamelContext.class);
+        exchangeFactory = mock(ExchangeFactory.class);
 
         List<IrcChannel> channels = new ArrayList<>();
         channels.add(new IrcChannel("#chan1", null));
@@ -53,6 +60,11 @@ public class IrcConsumerTest {
         when(configuration.getChannelList()).thenReturn(channels);
         when(endpoint.getConfiguration()).thenReturn(configuration);
 
+        when(endpoint.getCamelContext()).thenReturn(context);
+        when(context.adapt(ExtendedCamelContext.class)).thenReturn(context);
+        when(context.getExchangeFactory()).thenReturn(exchangeFactory);
+        when(exchangeFactory.newExchangeFactory(any())).thenReturn(exchangeFactory);
+
         consumer = new IrcConsumer(endpoint, processor, connection);
         consumer.setListener(listener);
     }
diff --git a/components/camel-ironmq/src/main/java/org/apache/camel/component/ironmq/IronMQConsumer.java b/components/camel-ironmq/src/main/java/org/apache/camel/component/ironmq/IronMQConsumer.java
index 8993614..30d45e2 100644
--- a/components/camel-ironmq/src/main/java/org/apache/camel/component/ironmq/IronMQConsumer.java
+++ b/components/camel-ironmq/src/main/java/org/apache/camel/component/ironmq/IronMQConsumer.java
@@ -59,7 +59,7 @@ public class IronMQConsumer extends ScheduledBatchPollingConsumer {
         shutdownRunningTask = null;
         pendingExchanges = 0;
         try {
-            Messages messages = null;
+            Messages messages;
             LOG.trace("Receiving messages with request [messagePerPoll {}, timeout {}]...", getMaxMessagesPerPoll(),
                     getEndpoint().getConfiguration().getTimeout());
             messages = this.ironQueue.reserve(getMaxMessagesPerPoll(), getEndpoint().getConfiguration().getTimeout(),
@@ -84,7 +84,7 @@ public class IronMQConsumer extends ScheduledBatchPollingConsumer {
 
         Queue<Exchange> answer = new LinkedList<>();
         for (Message message : messages) {
-            Exchange exchange = getEndpoint().createExchange(message);
+            Exchange exchange = createExchange(message);
             answer.add(exchange);
         }
         return answer;
@@ -172,4 +172,19 @@ public class IronMQConsumer extends ScheduledBatchPollingConsumer {
         return (IronMQEndpoint) super.getEndpoint();
     }
 
+    private Exchange createExchange(io.iron.ironmq.Message msg) {
+        Exchange exchange = createExchange(true);
+        exchange.setPattern(getEndpoint().getExchangePattern());
+        org.apache.camel.Message message = exchange.getIn();
+        if (getEndpoint().getConfiguration().isPreserveHeaders()) {
+            GsonUtil.copyFrom(msg, message);
+        } else {
+            message.setBody(msg.getBody());
+        }
+        message.setHeader(IronMQConstants.MESSAGE_ID, msg.getId());
+        message.setHeader(IronMQConstants.MESSAGE_RESERVATION_ID, msg.getReservationId());
+        message.setHeader(IronMQConstants.MESSAGE_RESERVED_COUNT, msg.getReservedCount());
+        return exchange;
+    }
+
 }
diff --git a/components/camel-ironmq/src/main/java/org/apache/camel/component/ironmq/IronMQEndpoint.java b/components/camel-ironmq/src/main/java/org/apache/camel/component/ironmq/IronMQEndpoint.java
index db0b244..4e8c116 100644
--- a/components/camel-ironmq/src/main/java/org/apache/camel/component/ironmq/IronMQEndpoint.java
+++ b/components/camel-ironmq/src/main/java/org/apache/camel/component/ironmq/IronMQEndpoint.java
@@ -22,9 +22,6 @@ import io.iron.ironmq.Client;
 import io.iron.ironmq.Cloud;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.spi.UriEndpoint;
@@ -74,24 +71,6 @@ public class IronMQEndpoint extends ScheduledPollEndpoint {
         return ironMQConsumer;
     }
 
-    public Exchange createExchange(io.iron.ironmq.Message msg) {
-        return createExchange(getExchangePattern(), msg);
-    }
-
-    private Exchange createExchange(ExchangePattern pattern, io.iron.ironmq.Message msg) {
-        Exchange exchange = super.createExchange(pattern);
-        Message message = exchange.getIn();
-        if (configuration.isPreserveHeaders()) {
-            GsonUtil.copyFrom(msg, message);
-        } else {
-            message.setBody(msg.getBody());
-        }
-        message.setHeader(IronMQConstants.MESSAGE_ID, msg.getId());
-        message.setHeader(IronMQConstants.MESSAGE_RESERVATION_ID, msg.getReservationId());
-        message.setHeader(IronMQConstants.MESSAGE_RESERVED_COUNT, msg.getReservedCount());
-        return exchange;
-    }
-
     @Override
     protected void doStart() throws Exception {
         super.doStart();
diff --git a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConsumer.java b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConsumer.java
index 343bfc7..a8d6c59 100644
--- a/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConsumer.java
+++ b/components/camel-jbpm/src/main/java/org/apache/camel/component/jbpm/JBPMConsumer.java
@@ -19,7 +19,6 @@ package org.apache.camel.component.jbpm;
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
 import org.apache.camel.Processor;
 import org.apache.camel.component.jbpm.emitters.CamelEventEmitter;
 import org.apache.camel.component.jbpm.listeners.CamelCaseEventListener;
@@ -98,7 +97,7 @@ public class JBPMConsumer extends DefaultConsumer implements DeploymentEventList
     }
 
     public void sendMessage(String eventType, Object body) {
-        Exchange exchange = getEndpoint().createExchange(ExchangePattern.InOnly);
+        Exchange exchange = createExchange(false);
         exchange.getIn().setHeader("EventType", eventType);
 
         exchange.getIn().setBody(body);
@@ -111,6 +110,7 @@ public class JBPMConsumer extends DefaultConsumer implements DeploymentEventList
                     if (exchange.getException() != null) {
                         getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
                     }
+                    releaseExchange(exchange, false);
                 }
             });
         } else {
@@ -124,6 +124,7 @@ public class JBPMConsumer extends DefaultConsumer implements DeploymentEventList
             if (exchange.getException() != null) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
             }
+            releaseExchange(exchange, false);
         }
     }
 
@@ -131,7 +132,6 @@ public class JBPMConsumer extends DefaultConsumer implements DeploymentEventList
     public void onDeploy(DeploymentEvent event) {
         InternalRuntimeManager manager = (InternalRuntimeManager) event.getDeployedUnit().getRuntimeManager();
         configure(manager, this);
-
     }
 
     @Override
@@ -156,7 +156,6 @@ public class JBPMConsumer extends DefaultConsumer implements DeploymentEventList
         }
 
         configureConsumer(eventListenerType, manager, consumer);
-
     }
 
     protected void configureConsumer(String eventListenerType, InternalRuntimeManager manager, JBPMConsumer consumer) {
diff --git a/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/server/CamelKieServerExtensionTest.java b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/server/CamelKieServerExtensionTest.java
index 11ce11c..0b1a559 100644
--- a/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/server/CamelKieServerExtensionTest.java
+++ b/components/camel-jbpm/src/test/java/org/apache/camel/component/jbpm/server/CamelKieServerExtensionTest.java
@@ -28,8 +28,6 @@ import org.jbpm.services.api.service.ServiceRegistry;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
-import org.kie.api.KieServices;
-import org.kie.api.runtime.Environment;
 import org.kie.api.runtime.KieContainer;
 import org.kie.internal.runtime.manager.InternalRuntimeManager;
 import org.kie.internal.runtime.manager.RuntimeEnvironment;
@@ -154,47 +152,4 @@ public class CamelKieServerExtensionTest {
         assertNull(context);
     }
 
-    @Test
-    public void testBuildDeploymentCamelContext() throws Exception {
-
-        when(runtimeManager.getIdentifier()).thenReturn(identifier);
-        when(runtimeManager.getEnvironment()).thenReturn(runtimeEnvironment);
-
-        Environment environment = KieServices.get().newEnvironment();
-        when(runtimeEnvironment.getEnvironment()).thenReturn(environment);
-
-        RuntimeManagerRegistry.get().register(runtimeManager);
-
-        CamelKieServerExtension extension = new CamelKieServerExtension();
-        CamelContext context = extension.buildDeploymentContext(identifier, this.getClass().getClassLoader());
-        assertNotNull(context);
-
-        context.stop();
-    }
-
-    @Test
-    public void testBuildDeploymentCamelContextCustomBuilder() throws Exception {
-
-        when(runtimeManager.getIdentifier()).thenReturn(identifier);
-        when(runtimeManager.getEnvironment()).thenReturn(runtimeEnvironment);
-
-        Environment environment = KieServices.get().newEnvironment();
-        environment.set(JBPMConstants.CAMEL_CONTEXT_BUILDER_KEY, new CamelContextBuilder() {
-
-            @Override
-            public CamelContext buildCamelContext() {
-                // for test purpose return simply null as camel context
-                return null;
-            }
-
-        });
-        when(runtimeEnvironment.getEnvironment()).thenReturn(environment);
-
-        RuntimeManagerRegistry.get().register(runtimeManager);
-
-        CamelKieServerExtension extension = new CamelKieServerExtension();
-        CamelContext context = extension.buildDeploymentContext(identifier, this.getClass().getClassLoader());
-        assertNull(context);
-
-    }
 }
diff --git a/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/JCacheConsumer.java b/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/JCacheConsumer.java
index 327e242..544a562 100644
--- a/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/JCacheConsumer.java
+++ b/components/camel-jcache/src/main/java/org/apache/camel/component/jcache/JCacheConsumer.java
@@ -28,14 +28,11 @@ import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.support.DefaultConsumer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * The JCache consumer.
  */
 public class JCacheConsumer extends DefaultConsumer {
-    private static final Logger LOG = LoggerFactory.getLogger(JCacheConsumer.class);
 
     private CacheEntryListenerConfiguration<Object, Object> entryListenerConfiguration;
 
@@ -83,7 +80,7 @@ public class JCacheConsumer extends DefaultConsumer {
                             @Override
                             protected void onEvents(Iterable<CacheEntryEvent<?, ?>> events) {
                                 for (CacheEntryEvent<?, ?> event : events) {
-                                    Exchange exchange = getEndpoint().createExchange();
+                                    Exchange exchange = createExchange(true);
                                     Message message = exchange.getIn();
                                     message.setHeader(JCacheConstants.EVENT_TYPE, event.getEventType().name());
                                     message.setHeader(JCacheConstants.KEY, event.getKey());
@@ -96,7 +93,7 @@ public class JCacheConsumer extends DefaultConsumer {
                                     try {
                                         getProcessor().process(exchange);
                                     } catch (Exception e) {
-                                        LOG.error("Error processing event ", e);
+                                        getExceptionHandler().handleException(e);
                                     }
                                 }
                             }
diff --git a/components/camel-jclouds/src/main/java/org/apache/camel/component/jclouds/JcloudsBlobStoreConsumer.java b/components/camel-jclouds/src/main/java/org/apache/camel/component/jclouds/JcloudsBlobStoreConsumer.java
index 899d323..7812704 100644
--- a/components/camel-jclouds/src/main/java/org/apache/camel/component/jclouds/JcloudsBlobStoreConsumer.java
+++ b/components/camel-jclouds/src/main/java/org/apache/camel/component/jclouds/JcloudsBlobStoreConsumer.java
@@ -75,7 +75,7 @@ public class JcloudsBlobStoreConsumer extends ScheduledBatchPollingConsumer {
                 if (!Strings.isNullOrEmpty(blobName)) {
                     InputStream body = JcloudsBlobStoreHelper.readBlob(blobStore, container, blobName);
                     if (body != null) {
-                        Exchange exchange = endpoint.createExchange();
+                        Exchange exchange = createExchange(true);
                         CachedOutputStream cos = new CachedOutputStream(exchange);
                         IOHelper.copy(body, cos);
                         exchange.getIn().setBody(cos.newStreamCache());
diff --git a/components/camel-jclouds/src/main/java/org/apache/camel/component/jclouds/JcloudsConsumer.java b/components/camel-jclouds/src/main/java/org/apache/camel/component/jclouds/JcloudsConsumer.java
deleted file mode 100644
index fdcef9c..0000000
--- a/components/camel-jclouds/src/main/java/org/apache/camel/component/jclouds/JcloudsConsumer.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.jclouds;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
-import org.apache.camel.support.ScheduledPollConsumer;
-
-public class JcloudsConsumer extends ScheduledPollConsumer {
-    private final JcloudsEndpoint endpoint;
-
-    public JcloudsConsumer(JcloudsEndpoint endpoint, Processor processor) {
-        super(endpoint, processor);
-        this.endpoint = endpoint;
-    }
-
-    @Override
-    protected int poll() throws Exception {
-        Exchange exchange = endpoint.createExchange();
-
-        try {
-            // send message to next processor in the route
-            getProcessor().process(exchange);
-            return 1; // number of messages polled
-        } finally {
-            // log exception if an exception occurred and was not handled
-            if (exchange.getException() != null) {
-                getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
-            }
-        }
-    }
-}
diff --git a/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/EndpointEventListener.java b/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/EndpointEventListener.java
index 4602722..abc06f6 100644
--- a/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/EndpointEventListener.java
+++ b/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/EndpointEventListener.java
@@ -38,10 +38,12 @@ public class EndpointEventListener implements EventListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(EndpointEventListener.class);
 
+    private final JcrConsumer consumer;
     private final JcrEndpoint endpoint;
     private final Processor processor;
 
-    public EndpointEventListener(JcrEndpoint endpoint, Processor processor) {
+    public EndpointEventListener(JcrConsumer consumer, JcrEndpoint endpoint, Processor processor) {
+        this.consumer = consumer;
         this.endpoint = endpoint;
         this.processor = processor;
     }
@@ -50,10 +52,10 @@ public class EndpointEventListener implements EventListener {
     public void onEvent(EventIterator events) {
         LOG.trace("onEvent START");
         LOG.debug("{} consumer received JCR events: {}", endpoint, events);
-        RuntimeCamelException rce = null;
+        RuntimeCamelException rce;
 
+        final Exchange exchange = createExchange(events);
         try {
-            final Exchange exchange = createExchange(events);
 
             try {
                 LOG.debug("Processor, {}, is processing exchange, {}", processor, exchange);
@@ -65,6 +67,8 @@ public class EndpointEventListener implements EventListener {
             rce = exchange.getException(RuntimeCamelException.class);
         } catch (Exception e) {
             rce = wrapRuntimeCamelException(e);
+        } finally {
+            consumer.releaseExchange(exchange, false);
         }
 
         if (rce != null) {
@@ -76,7 +80,7 @@ public class EndpointEventListener implements EventListener {
     }
 
     private Exchange createExchange(EventIterator events) {
-        Exchange exchange = endpoint.createExchange();
+        Exchange exchange = consumer.createExchange(false);
 
         List<Event> eventList = new LinkedList<>();
         if (events != null) {
diff --git a/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrConsumer.java b/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrConsumer.java
index ae7fd5d..9a39485 100644
--- a/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrConsumer.java
+++ b/components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrConsumer.java
@@ -108,7 +108,7 @@ public class JcrConsumer extends DefaultConsumer {
 
         boolean noLocal = getJcrEndpoint().isNoLocal();
 
-        eventListener = new EndpointEventListener(getJcrEndpoint(), getProcessor());
+        eventListener = new EndpointEventListener(this, getJcrEndpoint(), getProcessor());
 
         if (LOG.isDebugEnabled()) {
             LOG.debug("Adding JCR Event Listener, {}, on {}. eventTypes={}, isDeep={}, uuid={}, nodeTypeName={}, noLocal={}",
diff --git a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
index 013e00d..fdd4974 100644
--- a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
+++ b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
@@ -181,7 +181,8 @@ public class CamelContinuationServlet extends CamelServlet {
             }
 
             // a new request so create an exchange
-            final Exchange exchange = consumer.getEndpoint().createExchange(ExchangePattern.InOut);
+            final Exchange exchange = consumer.createExchange(false);
+            exchange.setPattern(ExchangePattern.InOut);
 
             if (consumer.getEndpoint().isBridgeEndpoint()) {
                 exchange.setProperty(Exchange.SKIP_GZIP_ENCODING, Boolean.TRUE);
@@ -268,6 +269,7 @@ public class CamelContinuationServlet extends CamelServlet {
             throw new ServletException(e);
         } finally {
             consumer.doneUoW(result);
+            consumer.releaseExchange(result, false);
         }
     }
 
diff --git a/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/CamelRoleChangeListener.java b/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/CamelRoleChangeListener.java
index 917e052..baf3325 100644
--- a/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/CamelRoleChangeListener.java
+++ b/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/CamelRoleChangeListener.java
@@ -21,7 +21,6 @@ import org.apache.camel.AsyncProcessor;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.support.AsyncProcessorConverterHelper;
-import org.apache.camel.util.ObjectHelper;
 import org.jgroups.protocols.raft.RAFT;
 import org.jgroups.protocols.raft.Role;
 import org.slf4j.Logger;
@@ -30,13 +29,12 @@ import org.slf4j.LoggerFactory;
 public class CamelRoleChangeListener implements RAFT.RoleChange {
     private static final transient Logger LOG = LoggerFactory.getLogger(CamelRoleChangeListener.class);
 
+    private final JGroupsRaftConsumer consumer;
     private final JGroupsRaftEndpoint endpoint;
     private final AsyncProcessor processor;
 
-    public CamelRoleChangeListener(JGroupsRaftEndpoint endpoint, Processor processor) {
-        ObjectHelper.notNull(endpoint, "endpoint");
-        ObjectHelper.notNull(processor, "processor");
-
+    public CamelRoleChangeListener(JGroupsRaftConsumer consumer, JGroupsRaftEndpoint endpoint, Processor processor) {
+        this.consumer = consumer;
         this.endpoint = endpoint;
         this.processor = AsyncProcessorConverterHelper.convert(processor);
     }
@@ -44,7 +42,7 @@ public class CamelRoleChangeListener implements RAFT.RoleChange {
     @Override
     public void roleChanged(Role role) {
         LOG.trace("New Role {} received.", role);
-        Exchange exchange = endpoint.createExchange();
+        Exchange exchange = createExchange();
         switch (role) {
             case Leader:
                 exchange.getIn().setHeader(JGroupsRaftConstants.HEADER_JGROUPSRAFT_EVENT_TYPE, JGroupsRaftEventType.LEADER);
@@ -76,4 +74,11 @@ public class CamelRoleChangeListener implements RAFT.RoleChange {
             throw new JGroupsRaftException("Error in consumer while dispatching exchange containing role " + role, e);
         }
     }
+
+    private Exchange createExchange() {
+        Exchange exchange = consumer.createExchange(true);
+        endpoint.populateJGroupsRaftHeaders(exchange);
+        return exchange;
+    }
+
 }
diff --git a/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/JGroupsRaftConsumer.java b/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/JGroupsRaftConsumer.java
index cf275c7..623b4d9 100644
--- a/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/JGroupsRaftConsumer.java
+++ b/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/JGroupsRaftConsumer.java
@@ -42,7 +42,7 @@ public class JGroupsRaftConsumer extends DefaultConsumer {
         this.clusterName = clusterName;
         this.enableRoleChangeEvents = enableRoleChangeEvents;
 
-        this.roleListener = new CamelRoleChangeListener(endpoint, processor);
+        this.roleListener = new CamelRoleChangeListener(this, endpoint, processor);
     }
 
     @Override
diff --git a/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/JGroupsRaftEndpoint.java b/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/JGroupsRaftEndpoint.java
index 3e0dfac..075f97e 100644
--- a/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/JGroupsRaftEndpoint.java
+++ b/components/camel-jgroups-raft/src/main/java/org/apache/camel/component/jgroups/raft/JGroupsRaftEndpoint.java
@@ -82,13 +82,6 @@ public class JGroupsRaftEndpoint extends DefaultEndpoint {
         return consumer;
     }
 
-    @Override
-    public Exchange createExchange() {
-        Exchange exchange = super.createExchange();
-        populateJGroupsRaftHeaders(exchange);
-        return exchange;
-    }
-
     public void populateJGroupsRaftHeaders(Exchange exchange) {
         exchange.getIn().setHeader(JGroupsRaftConstants.HEADER_JGROUPSRAFT_COMMIT_INDEX, resolvedRaftHandle.commitIndex());
         exchange.getIn().setHeader(JGroupsRaftConstants.HEADER_JGROUPSRAFT_CURRENT_TERM, resolvedRaftHandle.currentTerm());
diff --git a/components/camel-jgroups/src/main/java/org/apache/camel/component/jgroups/CamelJGroupsReceiver.java b/components/camel-jgroups/src/main/java/org/apache/camel/component/jgroups/CamelJGroupsReceiver.java
index 9fcdef8..4383903 100644
--- a/components/camel-jgroups/src/main/java/org/apache/camel/component/jgroups/CamelJGroupsReceiver.java
+++ b/components/camel-jgroups/src/main/java/org/apache/camel/component/jgroups/CamelJGroupsReceiver.java
@@ -21,13 +21,14 @@ import org.apache.camel.AsyncProcessor;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.support.AsyncProcessorConverterHelper;
-import org.apache.camel.util.ObjectHelper;
 import org.jgroups.Message;
 import org.jgroups.ReceiverAdapter;
 import org.jgroups.View;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.camel.component.jgroups.JGroupsEndpoint.HEADER_JGROUPS_CHANNEL_ADDRESS;
+
 /**
  * Implementation of JGroups message receiver ({@code org.jgroups.Receiver}) wrapping incoming messages into Camel
  * exchanges. Used by {@link JGroupsConsumer}.
@@ -36,13 +37,12 @@ public class CamelJGroupsReceiver extends ReceiverAdapter {
 
     private static final transient Logger LOG = LoggerFactory.getLogger(CamelJGroupsReceiver.class);
 
+    private final JGroupsConsumer consumer;
     private final JGroupsEndpoint endpoint;
     private final AsyncProcessor processor;
 
-    public CamelJGroupsReceiver(JGroupsEndpoint endpoint, Processor processor) {
-        ObjectHelper.notNull(endpoint, "endpoint");
-        ObjectHelper.notNull(processor, "processor");
-
+    public CamelJGroupsReceiver(JGroupsConsumer consumer, JGroupsEndpoint endpoint, Processor processor) {
+        this.consumer = consumer;
         this.endpoint = endpoint;
         this.processor = AsyncProcessorConverterHelper.convert(processor);
     }
@@ -50,7 +50,7 @@ public class CamelJGroupsReceiver extends ReceiverAdapter {
     @Override
     public void viewAccepted(View view) {
         if (endpoint.isEnableViewMessages()) {
-            Exchange exchange = endpoint.createExchange(view);
+            Exchange exchange = createExchange(view);
             try {
                 LOG.debug("Processing view: {}", view);
                 processor.process(exchange, new AsyncCallback() {
@@ -80,4 +80,11 @@ public class CamelJGroupsReceiver extends ReceiverAdapter {
         }
     }
 
+    public Exchange createExchange(View view) {
+        Exchange exchange = consumer.createExchange(true);
+        exchange.getIn().setHeader(HEADER_JGROUPS_CHANNEL_ADDRESS, endpoint.getResolvedChannel().getAddress());
+        exchange.getIn().setBody(view);
+        return exchange;
+    }
+
 }
diff --git a/components/camel-jgroups/src/main/java/org/apache/camel/component/jgroups/JGroupsConsumer.java b/components/camel-jgroups/src/main/java/org/apache/camel/component/jgroups/JGroupsConsumer.java
index 7cb4e90..bb8ce3e 100644
--- a/components/camel-jgroups/src/main/java/org/apache/camel/component/jgroups/JGroupsConsumer.java
+++ b/components/camel-jgroups/src/main/java/org/apache/camel/component/jgroups/JGroupsConsumer.java
@@ -40,7 +40,7 @@ public class JGroupsConsumer extends DefaultConsumer {
         this.endpoint = endpoint;
         this.clusterName = clusterName;
 
-        this.receiver = new CamelJGroupsReceiver(endpoint, processor);
+        this.receiver = new CamelJGroupsReceiver(this, endpoint, processor);
     }
 
     @Override
diff --git a/components/camel-jgroups/src/test/java/org/apache/camel/component/jgroups/CamelJGroupsReceiverTest.java b/components/camel-jgroups/src/test/java/org/apache/camel/component/jgroups/CamelJGroupsReceiverTest.java
deleted file mode 100644
index b81c436..0000000
--- a/components/camel-jgroups/src/test/java/org/apache/camel/component/jgroups/CamelJGroupsReceiverTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.jgroups;
-
-import org.apache.camel.Processor;
-import org.jgroups.Message;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.ArgumentMatchers;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.BDDMockito.willThrow;
-
-@ExtendWith(MockitoExtension.class)
-public class CamelJGroupsReceiverTest {
-
-    // Fixtures
-
-    @InjectMocks
-    CamelJGroupsReceiver receiver;
-
-    @Mock
-    JGroupsEndpoint jGroupsEndpoint;
-
-    @Mock
-    Processor processor;
-
-    // Tests
-
-    @Test
-    public void shouldHandleProcessingException() throws Exception {
-        // Given
-        willThrow(Exception.class).given(processor).process(ArgumentMatchers.isNull());
-        Message message = new Message(null, "someMessage");
-        message.setSrc(null);
-        // When
-        assertThrows(JGroupsException.class,
-                () -> receiver.receive(message));
-    }
-
-}
diff --git a/components/camel-jira/src/main/java/org/apache/camel/component/jira/JiraConstants.java b/components/camel-jira/src/main/java/org/apache/camel/component/jira/JiraConstants.java
index d53dd95..7f9ed14 100644
--- a/components/camel-jira/src/main/java/org/apache/camel/component/jira/JiraConstants.java
+++ b/components/camel-jira/src/main/java/org/apache/camel/component/jira/JiraConstants.java
@@ -27,6 +27,7 @@ public interface JiraConstants {
     String ISSUE_ASSIGNEE = "IssueAssignee";
     String ISSUE_COMPONENTS = "IssueComponents";
     String ISSUE_COMMENT = "IssueComment";
+    String ISSUE_CHANGED = "IssueChanged";
     String ISSUE_KEY = "IssueKey";
     String ISSUE_PRIORITY_ID = "IssuePriorityId";
     String ISSUE_PRIORITY_NAME = "IssuePriorityName";
@@ -35,6 +36,7 @@ public interface JiraConstants {
     String ISSUE_TRANSITION_ID = "IssueTransitionId";
     String ISSUE_TYPE_ID = "IssueTypeId";
     String ISSUE_TYPE_NAME = "IssueTypeName";
+    String ISSUE_WATCHED_ISSUES = "IssueWatchedIssues";
     String ISSUE_WATCHERS_ADD = "IssueWatchersAdd";
     String ISSUE_WATCHERS_REMOVE = "IssueWatchersRemove";
     String JIRA_REST_CLIENT_FACTORY = "JiraRestClientFactory";
diff --git a/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/NewCommentsConsumer.java b/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/NewCommentsConsumer.java
index 0b080fb..00c0b38 100644
--- a/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/NewCommentsConsumer.java
+++ b/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/NewCommentsConsumer.java
@@ -52,7 +52,7 @@ public class NewCommentsConsumer extends AbstractJiraConsumer {
         // retrieve from last to first item LIFO
         for (int i = max; i > -1; i--) {
             Comment newComment = newComments.get(i);
-            Exchange e = getEndpoint().createExchange();
+            Exchange e = createExchange(true);
             e.getIn().setBody(newComment);
             getProcessor().process(e);
         }
diff --git a/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/NewIssuesConsumer.java b/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/NewIssuesConsumer.java
index b2fd19e..b5d09ef 100644
--- a/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/NewIssuesConsumer.java
+++ b/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/NewIssuesConsumer.java
@@ -61,7 +61,7 @@ public class NewIssuesConsumer extends AbstractJiraConsumer {
             // In the end, we want only *new* issues oldest to newest.
             for (int i = newIssues.size() - 1; i > -1; i--) {
                 Issue newIssue = newIssues.get(i);
-                Exchange e = getEndpoint().createExchange();
+                Exchange e = createExchange(true);
                 e.getIn().setBody(newIssue);
                 getProcessor().process(e);
             }
diff --git a/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/WatchUpdatesConsumer.java b/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/WatchUpdatesConsumer.java
index a97d5fb..6a512c5 100644
--- a/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/WatchUpdatesConsumer.java
+++ b/components/camel-jira/src/main/java/org/apache/camel/component/jira/consumer/WatchUpdatesConsumer.java
@@ -29,6 +29,7 @@ import java.util.stream.Collectors;
 import com.atlassian.jira.rest.client.api.domain.Issue;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
+import org.apache.camel.component.jira.JiraConstants;
 import org.apache.camel.component.jira.JiraEndpoint;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -107,11 +108,11 @@ public class WatchUpdatesConsumer extends AbstractJiraConsumer {
     }
 
     private void processExchange(Object body, String issueKey, String changed) throws Exception {
-        Exchange e = getEndpoint().createExchange();
+        Exchange e = createExchange(true);
         e.getIn().setBody(body);
-        e.getIn().setHeader("issueKey", issueKey);
-        e.getIn().setHeader("changed", changed);
-        e.getIn().setHeader("watchedIssues", watchedIssuesKeys);
+        e.getIn().setHeader(JiraConstants.ISSUE_KEY, issueKey);
+        e.getIn().setHeader(JiraConstants.ISSUE_CHANGED, changed);
+        e.getIn().setHeader(JiraConstants.ISSUE_WATCHED_ISSUES, watchedIssuesKeys);
         LOG.debug(" {}: {} changed to {}", issueKey, changed, body);
         getProcessor().process(e);
     }
diff --git a/components/camel-jira/src/test/java/org/apache/camel/component/jira/consumer/WatchUpdatesConsumerTest.java b/components/camel-jira/src/test/java/org/apache/camel/component/jira/consumer/WatchUpdatesConsumerTest.java
index f6c7c0e..369393f 100644
--- a/components/camel-jira/src/test/java/org/apache/camel/component/jira/consumer/WatchUpdatesConsumerTest.java
+++ b/components/camel-jira/src/test/java/org/apache/camel/component/jira/consumer/WatchUpdatesConsumerTest.java
@@ -33,6 +33,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.EndpointInject;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.jira.JiraComponent;
+import org.apache.camel.component.jira.JiraConstants;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.spi.Registry;
 import org.apache.camel.test.junit5.CamelTestSupport;
@@ -132,8 +133,8 @@ public class WatchUpdatesConsumerTest extends CamelTestSupport {
         });
 
         mockResult.expectedBodiesReceived(issue.getPriority());
-        mockResult.expectedHeaderReceived("changed", "Priority");
-        mockResult.expectedHeaderReceived("issueKey", "TST-1");
+        mockResult.expectedHeaderReceived(JiraConstants.ISSUE_CHANGED, "Priority");
+        mockResult.expectedHeaderReceived(JiraConstants.ISSUE_KEY, "TST-1");
         mockResult.expectedMessageCount(1);
         mockResult.assertIsSatisfied(0);
     }
diff --git a/components/camel-jms/src/main/java/org/apache/camel/component/jms/EndpointMessageListener.java b/components/camel-jms/src/main/java/org/apache/camel/component/jms/EndpointMessageListener.java
index 05225c2..872b2af 100644
--- a/components/camel-jms/src/main/java/org/apache/camel/component/jms/EndpointMessageListener.java
+++ b/components/camel-jms/src/main/java/org/apache/camel/component/jms/EndpointMessageListener.java
@@ -26,6 +26,7 @@ import org.apache.camel.AsyncCallback;
 import org.apache.camel.AsyncProcessor;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
+import org.apache.camel.ExtendedExchange;
 import org.apache.camel.Processor;
 import org.apache.camel.RollbackExchangeException;
 import org.apache.camel.RuntimeCamelException;
@@ -45,6 +46,7 @@ import static org.apache.camel.RuntimeCamelException.wrapRuntimeCamelException;
  */
 public class EndpointMessageListener implements SessionAwareMessageListener {
     private static final Logger LOG = LoggerFactory.getLogger(EndpointMessageListener.class);
+    private final JmsConsumer consumer;
     private final JmsEndpoint endpoint;
     private final AsyncProcessor processor;
     private JmsBinding binding;
@@ -55,7 +57,8 @@ public class EndpointMessageListener implements SessionAwareMessageListener {
     private boolean disableReplyTo;
     private boolean async;
 
-    public EndpointMessageListener(JmsEndpoint endpoint, Processor processor) {
+    public EndpointMessageListener(JmsConsumer consumer, JmsEndpoint endpoint, Processor processor) {
+        this.consumer = consumer;
         this.endpoint = endpoint;
         this.processor = AsyncProcessorConverterHelper.convert(processor);
     }
@@ -147,6 +150,9 @@ public class EndpointMessageListener implements SessionAwareMessageListener {
             // if we failed processed the exchange from the async callback task, then grab the exception
             rce = exchange.getException(RuntimeCamelException.class);
 
+            // the exchange is now done so release it
+            consumer.releaseExchange(exchange, false);
+
         } catch (Exception e) {
             rce = wrapRuntimeCamelException(e);
         }
@@ -250,14 +256,30 @@ public class EndpointMessageListener implements SessionAwareMessageListener {
                     }
                 }
             }
+
+            // if we completed from async processing then we should release the exchange
+            // the sync processing will release the exchange outside this callback
+            if (!doneSync) {
+                consumer.releaseExchange(exchange, false);
+            }
         }
     }
 
     public Exchange createExchange(Message message, Session session, Object replyDestination) {
-        Exchange exchange = endpoint.createExchange();
+        Exchange exchange = consumer.createExchange(false);
         JmsBinding binding = getBinding();
         exchange.setProperty(Exchange.BINDING, binding);
-        exchange.setIn(new JmsMessage(exchange, message, session, binding));
+
+        // optimize: either create a new JmsMessage or reuse existing if exists
+        JmsMessage msg = exchange.adapt(ExtendedExchange.class).getInOrNull(JmsMessage.class);
+        if (msg == null) {
+            msg = new JmsMessage(exchange, message, session, binding);
+            exchange.setIn(msg);
+        } else {
+            msg.setJmsMessage(message);
+            msg.setJmsSession(session);
+            msg.setBinding(binding);
+        }
 
         // lets set to an InOut if we have some kind of reply-to destination
         if (replyDestination != null && !disableReplyTo) {
diff --git a/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsConsumer.java b/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsConsumer.java
index 3fafd18..98fce1d 100644
--- a/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsConsumer.java
+++ b/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsConsumer.java
@@ -75,7 +75,7 @@ public class JmsConsumer extends DefaultConsumer implements Suspendable {
     }
 
     protected void createMessageListener(JmsEndpoint endpoint, Processor processor) {
-        messageListener = new EndpointMessageListener(endpoint, processor);
+        messageListener = new EndpointMessageListener(this, endpoint, processor);
         getEndpoint().getConfiguration().configureMessageListener(messageListener);
         messageListener.setBinding(endpoint.getBinding());
         messageListener.setAsync(endpoint.getConfiguration().isAsyncConsumer());
diff --git a/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsMessage.java b/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsMessage.java
index b3efa26..3c8925a 100644
--- a/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsMessage.java
+++ b/components/camel-jms/src/main/java/org/apache/camel/component/jms/JmsMessage.java
@@ -51,6 +51,14 @@ public class JmsMessage extends DefaultMessage {
     }
 
     @Override
+    public void reset() {
+        super.reset();
+        jmsMessage = null;
+        jmsSession = null;
+        binding = null;
+    }
+
+    @Override
     public String toString() {
         // do not print jmsMessage as there could be sensitive details
         if (jmsMessage != null) {
diff --git a/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyConsumerQueueTest.java b/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsInOnlyPooledExchangeTest.java
similarity index 51%
copy from components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyConsumerQueueTest.java
copy to components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsInOnlyPooledExchangeTest.java
index b55fec2..6d19057 100644
--- a/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyConsumerQueueTest.java
+++ b/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsInOnlyPooledExchangeTest.java
@@ -14,16 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.sjms.consumer;
+package org.apache.camel.component.jms;
 
+import javax.jms.ConnectionFactory;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.component.sjms.support.JmsTestSupport;
+import org.apache.camel.impl.engine.PooledExchangeFactory;
+import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
 
-public class InOnlyConsumerQueueTest extends JmsTestSupport {
+import static org.apache.camel.component.jms.JmsComponent.jmsComponentAutoAcknowledge;
+
+public class JmsInOnlyPooledExchangeTest extends CamelTestSupport {
 
-    private static final String SJMS_QUEUE_NAME = "sjms:queue:in.only.consumer.queue";
+    private static final String JMS_QUEUE_NAME = "activemq:queue:foo";
     private static final String MOCK_RESULT = "mock:result";
 
     @Test
@@ -33,19 +40,40 @@ public class InOnlyConsumerQueueTest extends JmsTestSupport {
         mock.expectedMessageCount(1);
         mock.expectedBodiesReceived(expectedBody);
 
-        template.sendBody(SJMS_QUEUE_NAME, expectedBody);
+        template.sendBody(JMS_QUEUE_NAME, expectedBody);
+
+        mock.assertIsSatisfied();
+    }
+
+    @Test
+    public void testTwoSynchronous() throws Exception {
+        MockEndpoint mock = getMockEndpoint(MOCK_RESULT);
+        mock.expectedBodiesReceived("Hello World", "Bye World");
+
+        template.sendBody(JMS_QUEUE_NAME, "Hello World");
+        template.sendBody(JMS_QUEUE_NAME, "Bye World");
 
         mock.assertIsSatisfied();
     }
 
     @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext camelContext = super.createCamelContext();
+        camelContext.adapt(ExtendedCamelContext.class).setExchangeFactory(new PooledExchangeFactory());
+
+        ConnectionFactory connectionFactory = CamelJmsTestHelper.createConnectionFactory();
+        camelContext.addComponent("activemq", jmsComponentAutoAcknowledge(connectionFactory));
+        return camelContext;
+    }
+
+    @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
+            @Override
             public void configure() throws Exception {
-                from(SJMS_QUEUE_NAME)
+                from(JMS_QUEUE_NAME)
                         .to(MOCK_RESULT);
             }
         };
     }
-
 }
diff --git a/components/camel-jmx/src/main/java/org/apache/camel/component/jmx/JMXConsumer.java b/components/camel-jmx/src/main/java/org/apache/camel/component/jmx/JMXConsumer.java
index 18171a3..7fa7853 100644
--- a/components/camel-jmx/src/main/java/org/apache/camel/component/jmx/JMXConsumer.java
+++ b/components/camel-jmx/src/main/java/org/apache/camel/component/jmx/JMXConsumer.java
@@ -319,7 +319,7 @@ public class JMXConsumer extends DefaultConsumer implements NotificationListener
     @Override
     public void handleNotification(Notification aNotification, Object aHandback) {
         JMXEndpoint ep = getEndpoint();
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         Message message = exchange.getIn();
         message.setHeader("jmx.handback", aHandback);
         try {
@@ -329,7 +329,7 @@ public class JMXConsumer extends DefaultConsumer implements NotificationListener
                 message.setBody(aNotification);
             }
 
-            // process the notification from thred pool to not block this notification callback thread from the JVM
+            // process the notification from thread pool to not block this notification callback thread from the JVM
             executorService.submit(() -> {
                 try {
                     getProcessor().process(exchange);
diff --git a/components/camel-jooq/src/main/java/org/apache/camel/component/jooq/JooqConsumer.java b/components/camel-jooq/src/main/java/org/apache/camel/component/jooq/JooqConsumer.java
index b2868e3..b7ac8e2 100644
--- a/components/camel-jooq/src/main/java/org/apache/camel/component/jooq/JooqConsumer.java
+++ b/components/camel-jooq/src/main/java/org/apache/camel/component/jooq/JooqConsumer.java
@@ -78,7 +78,7 @@ public class JooqConsumer extends ScheduledBatchPollingConsumer {
     }
 
     protected Exchange createExchange(Object result) {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setBody(result);
         return exchange;
     }
diff --git a/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaConsumer.java b/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaConsumer.java
index 6bb0774..cf99d19 100644
--- a/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaConsumer.java
+++ b/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaConsumer.java
@@ -144,7 +144,7 @@ public class JpaConsumer extends ScheduledBatchPollingConsumer {
                                     "Error processing last message due: {}. Will commit all previous successful processed message, and ignore this last failure.",
                                     cause.getMessage(), cause);
                         } else {
-                            // rollback all by throwning exception
+                            // rollback all by throwing exception
                             throw cause;
                         }
                     }
@@ -200,14 +200,23 @@ public class JpaConsumer extends ScheduledBatchPollingConsumer {
 
                 // process the current exchange
                 LOG.debug("Processing exchange: {}", exchange);
-                getProcessor().process(exchange);
-                if (exchange.getException() != null) {
-                    // if we failed then throw exception
-                    throw exchange.getException();
+                try {
+                    getProcessor().process(exchange);
+                } catch (Exception e) {
+                    exchange.setException(e);
                 }
 
-                // Run the @Consumed callback
-                getDeleteHandler().deleteObject(entityManager, result, exchange);
+                try {
+                    if (exchange.getException() != null) {
+                        // if we failed then throw exception
+                        throw exchange.getException();
+                    } else {
+                        // Run the @Consumed callback
+                        getDeleteHandler().deleteObject(entityManager, result, exchange);
+                    }
+                } finally {
+                    releaseExchange(exchange, false);
+                }
             }
         }
 
@@ -514,7 +523,7 @@ public class JpaConsumer extends ScheduledBatchPollingConsumer {
     }
 
     protected Exchange createExchange(Object result, EntityManager entityManager) {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(false);
         exchange.getIn().setBody(result);
         exchange.getIn().setHeader(JpaConstants.ENTITY_MANAGER, entityManager);
         return exchange;
diff --git a/components/camel-jt400/src/main/java/org/apache/camel/component/jt400/Jt400DataQueueConsumer.java b/components/camel-jt400/src/main/java/org/apache/camel/component/jt400/Jt400DataQueueConsumer.java
index d73ae11..e7f113c 100644
--- a/components/camel-jt400/src/main/java/org/apache/camel/component/jt400/Jt400DataQueueConsumer.java
+++ b/components/camel-jt400/src/main/java/org/apache/camel/component/jt400/Jt400DataQueueConsumer.java
@@ -152,7 +152,7 @@ public class Jt400DataQueueConsumer extends ScheduledPollConsumer {
             entry = queue.read(key, -1, searchType);
         }
 
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         if (entry != null) {
             exchange.getIn().setHeader(Jt400Endpoint.SENDER_INFORMATION, entry.getSenderInformation());
             if (getEndpoint().getFormat() == Jt400Configuration.Format.binary) {
diff --git a/components/camel-jt400/src/main/java/org/apache/camel/component/jt400/Jt400MsgQueueConsumer.java b/components/camel-jt400/src/main/java/org/apache/camel/component/jt400/Jt400MsgQueueConsumer.java
index 5dbbe93..8dac242 100755
--- a/components/camel-jt400/src/main/java/org/apache/camel/component/jt400/Jt400MsgQueueConsumer.java
+++ b/components/camel-jt400/src/main/java/org/apache/camel/component/jt400/Jt400MsgQueueConsumer.java
@@ -121,7 +121,7 @@ public class Jt400MsgQueueConsumer extends ScheduledPollConsumer {
             this.messageKey = entry.getKey();
         }
 
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getIn().setHeader(Jt400Constants.SENDER_INFORMATION,
                 entry.getFromJobNumber() + "/" + entry.getUser() + "/" + entry.getFromJobName());
         setHeaderIfValueNotNull(exchange.getIn(), Jt400Constants.MESSAGE_ID, entry.getID());
diff --git a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaConsumer.java b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaConsumer.java
index b911881..7078044 100644
--- a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaConsumer.java
+++ b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaConsumer.java
@@ -33,6 +33,7 @@ import java.util.regex.Pattern;
 import java.util.stream.StreamSupport;
 
 import org.apache.camel.Exchange;
+import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.component.kafka.serde.KafkaHeaderDeserializer;
 import org.apache.camel.spi.HeaderFilterStrategy;
@@ -239,8 +240,7 @@ public class KafkaConsumer extends DefaultConsumer {
 
         @SuppressWarnings("unchecked")
         protected boolean doRun() {
-            // allow to re-connect thread in case we use that to retry failed
-            // messages
+            // allow to re-connect thread in case we use that to retry failed messages
             boolean reConnect = false;
             boolean unsubscribing = false;
 
@@ -320,7 +320,7 @@ public class KafkaConsumer extends DefaultConsumer {
                                     LOG.trace("Partition = {}, offset = {}, key = {}, value = {}", record.partition(),
                                             record.offset(), record.key(), record.value());
                                 }
-                                Exchange exchange = endpoint.createKafkaExchange(record);
+                                Exchange exchange = createKafkaExchange(record);
 
                                 propagateHeaders(record, exchange, endpoint.getConfiguration());
 
@@ -355,14 +355,11 @@ public class KafkaConsumer extends DefaultConsumer {
                                     // processing failed due to an unhandled
                                     // exception, what should we do
                                     if (endpoint.getConfiguration().isBreakOnFirstError()) {
-                                        // we are failing and we should break
-                                        // out
+                                        // we are failing and we should break out
                                         LOG.warn(
                                                 "Error during processing {} from topic: {}. Will seek consumer to offset: {} and re-connect and start polling again.",
-                                                exchange,
-                                                topicName, partitionLastOffset, exchange.getException());
-                                        // force commit so we resume on next
-                                        // poll where we failed
+                                                exchange, topicName, partitionLastOffset, exchange.getException());
+                                        // force commit so we resume on next poll where we failed
                                         commitOffset(offsetRepository, partition, partitionLastOffset, true);
                                         // continue to next partition
                                         breakOnErrorHit = true;
@@ -380,6 +377,9 @@ public class KafkaConsumer extends DefaultConsumer {
                                     // offset state upon partition revoke
                                     lastProcessedOffset.put(serializeOffsetKey(partition), partitionLastOffset);
                                 }
+
+                                // success so release the exchange
+                                releaseExchange(exchange, false);
                             }
 
                             if (!breakOnErrorHit) {
@@ -506,6 +506,24 @@ public class KafkaConsumer extends DefaultConsumer {
         }
     }
 
+    @SuppressWarnings("rawtypes")
+    private Exchange createKafkaExchange(ConsumerRecord record) {
+        Exchange exchange = createExchange(false);
+
+        Message message = exchange.getIn();
+        message.setHeader(KafkaConstants.PARTITION, record.partition());
+        message.setHeader(KafkaConstants.TOPIC, record.topic());
+        message.setHeader(KafkaConstants.OFFSET, record.offset());
+        message.setHeader(KafkaConstants.HEADERS, record.headers());
+        message.setHeader(KafkaConstants.TIMESTAMP, record.timestamp());
+        if (record.key() != null) {
+            message.setHeader(KafkaConstants.KEY, record.key());
+        }
+        message.setBody(record.value());
+
+        return exchange;
+    }
+
     private void propagateHeaders(
             ConsumerRecord<Object, Object> record, Exchange exchange, KafkaConfiguration kafkaConfiguration) {
         HeaderFilterStrategy headerFilterStrategy = kafkaConfiguration.getHeaderFilterStrategy();
diff --git a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaEndpoint.java b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaEndpoint.java
index 2ffc47e..950cbfa 100644
--- a/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaEndpoint.java
+++ b/components/camel-kafka/src/main/java/org/apache/camel/component/kafka/KafkaEndpoint.java
@@ -21,8 +21,6 @@ import java.util.concurrent.ExecutorService;
 
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
 import org.apache.camel.MultipleConsumersSupport;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
@@ -33,7 +31,6 @@ import org.apache.camel.support.DefaultEndpoint;
 import org.apache.camel.support.SynchronousDelegateProducer;
 import org.apache.camel.util.CastUtils;
 import org.apache.kafka.clients.consumer.ConsumerConfig;
-import org.apache.kafka.clients.consumer.ConsumerRecord;
 import org.apache.kafka.clients.producer.Partitioner;
 import org.apache.kafka.clients.producer.ProducerConfig;
 import org.apache.kafka.common.serialization.Deserializer;
@@ -146,24 +143,6 @@ public class KafkaEndpoint extends DefaultEndpoint implements MultipleConsumersS
                 "KafkaProducer[" + configuration.getTopic() + "]", core, max);
     }
 
-    @SuppressWarnings("rawtypes")
-    public Exchange createKafkaExchange(ConsumerRecord record) {
-        Exchange exchange = super.createExchange();
-
-        Message message = exchange.getIn();
-        message.setHeader(KafkaConstants.PARTITION, record.partition());
-        message.setHeader(KafkaConstants.TOPIC, record.topic());
-        message.setHeader(KafkaConstants.OFFSET, record.offset());
-        message.setHeader(KafkaConstants.HEADERS, record.headers());
-        message.setHeader(KafkaConstants.TIMESTAMP, record.timestamp());
-        if (record.key() != null) {
-            message.setHeader(KafkaConstants.KEY, record.key());
-        }
-        message.setBody(record.value());
-
-        return exchange;
-    }
-
     protected KafkaProducer createProducer(KafkaEndpoint endpoint) {
         return new KafkaProducer(endpoint);
     }
diff --git a/components/camel-kafka/src/test/java/org/apache/camel/component/kafka/KafkaConsumerTest.java b/components/camel-kafka/src/test/java/org/apache/camel/component/kafka/KafkaConsumerTest.java
index eff7f14..7bad317 100644
--- a/components/camel-kafka/src/test/java/org/apache/camel/component/kafka/KafkaConsumerTest.java
+++ b/components/camel-kafka/src/test/java/org/apache/camel/component/kafka/KafkaConsumerTest.java
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.component.kafka;
 
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Processor;
+import org.apache.camel.spi.ExchangeFactory;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -31,9 +33,15 @@ public class KafkaConsumerTest {
     private KafkaComponent component = mock(KafkaComponent.class);
     private KafkaEndpoint endpoint = mock(KafkaEndpoint.class);
     private Processor processor = mock(Processor.class);
+    private ExtendedCamelContext ecc = mock(ExtendedCamelContext.class);
+    private ExchangeFactory ef = mock(ExchangeFactory.class);
 
     @Test
     public void consumerRequiresBootstrapServers() throws Exception {
+        when(endpoint.getCamelContext()).thenReturn(ecc);
+        when(ecc.adapt(ExtendedCamelContext.class)).thenReturn(ecc);
+        when(ecc.getExchangeFactory()).thenReturn(ef);
+        when(ef.newExchangeFactory(any())).thenReturn(ef);
         when(endpoint.getComponent()).thenReturn(component);
         when(endpoint.getConfiguration()).thenReturn(configuration);
         when(endpoint.getConfiguration().getGroupId()).thenReturn("groupOne");
@@ -45,6 +53,10 @@ public class KafkaConsumerTest {
 
     @Test
     public void consumerOnlyRequiresBootstrapServers() throws Exception {
+        when(endpoint.getCamelContext()).thenReturn(ecc);
+        when(ecc.adapt(ExtendedCamelContext.class)).thenReturn(ecc);
+        when(ecc.getExchangeFactory()).thenReturn(ef);
+        when(ef.newExchangeFactory(any())).thenReturn(ef);
         when(endpoint.getComponent()).thenReturn(component);
         when(endpoint.getConfiguration()).thenReturn(configuration);
         when(endpoint.getConfiguration().getBrokers()).thenReturn("localhost:2181");
diff --git a/components/camel-kafka/src/test/java/org/apache/camel/component/kafka/KafkaEndpointTest.java b/components/camel-kafka/src/test/java/org/apache/camel/component/kafka/KafkaEndpointTest.java
deleted file mode 100644
index 0533013..0000000
--- a/components/camel-kafka/src/test/java/org/apache/camel/component/kafka/KafkaEndpointTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.kafka;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
-import org.apache.camel.impl.DefaultCamelContext;
-import org.apache.kafka.clients.consumer.ConsumerRecord;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoSettings;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.Mockito.when;
-
-@MockitoSettings
-public class KafkaEndpointTest {
-
-    private KafkaEndpoint endpoint;
-
-    @Mock
-    private ConsumerRecord<String, String> mockRecord;
-
-    @Mock
-    private KafkaComponent mockKafkaComponent;
-
-    @BeforeEach
-    public void setup() {
-        KafkaComponent kafka = new KafkaComponent(new DefaultCamelContext());
-        kafka.init();
-        endpoint = new KafkaEndpoint("kafka:mytopic?brokers=localhost", kafka);
-    }
-
-    @Test
-    public void createKafkaExchangeShouldSetHeaders() {
-
-        when(mockRecord.key()).thenReturn("somekey");
-        when(mockRecord.topic()).thenReturn("topic");
-        when(mockRecord.partition()).thenReturn(4);
-        when(mockRecord.offset()).thenReturn(56L);
-        when(mockRecord.timestamp()).thenReturn(1518026587392L);
-
-        Exchange exchange = endpoint.createKafkaExchange(mockRecord);
-        Message inMessage = exchange.getIn();
-        assertNotNull(inMessage);
-        assertEquals("somekey", inMessage.getHeader(KafkaConstants.KEY));
-        assertEquals("topic", inMessage.getHeader(KafkaConstants.TOPIC));
-        assertEquals(4, inMessage.getHeader(KafkaConstants.PARTITION));
-        assertEquals(56L, inMessage.getHeader(KafkaConstants.OFFSET));
-        assertEquals(1518026587392L, inMessage.getHeader(KafkaConstants.TIMESTAMP));
-    }
-
-    @Test
-    public void isSingletonShouldReturnTrue() {
-        assertTrue(endpoint.isSingleton());
-    }
-
-}
diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/config_maps/KubernetesConfigMapsConsumer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/config_maps/KubernetesConfigMapsConsumer.java
index b33b737..5df45d0 100644
--- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/config_maps/KubernetesConfigMapsConsumer.java
+++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/config_maps/KubernetesConfigMapsConsumer.java
@@ -110,7 +110,7 @@ public class KubernetesConfigMapsConsumer extends DefaultConsumer {
                 @Override
                 public void eventReceived(io.fabric8.kubernetes.client.Watcher.Action action, ConfigMap resource) {
                     ConfigMapEvent de = new ConfigMapEvent(action, resource);
-                    Exchange exchange = getEndpoint().createExchange();
+                    Exchange exchange = createExchange(false);
                     exchange.getIn().setBody(de.getConfigMap());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_ACTION, de.getAction());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_TIMESTAMP, System.currentTimeMillis());
@@ -118,6 +118,8 @@ public class KubernetesConfigMapsConsumer extends DefaultConsumer {
                         processor.process(exchange);
                     } catch (Exception e) {
                         getExceptionHandler().handleException("Error during processing", exchange, e);
+                    } finally {
+                        releaseExchange(exchange, false);
                     }
                 }
 
diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/customresources/KubernetesCustomResourcesConsumer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/customresources/KubernetesCustomResourcesConsumer.java
index 8ce8010..0e22f9b 100644
--- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/customresources/KubernetesCustomResourcesConsumer.java
+++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/customresources/KubernetesCustomResourcesConsumer.java
@@ -97,7 +97,7 @@ public class KubernetesCustomResourcesConsumer extends DefaultConsumer {
 
                     @Override
                     public void eventReceived(Action action, String resource) {
-                        Exchange exchange = getEndpoint().createExchange();
+                        Exchange exchange = createExchange(false);
                         exchange.getIn().setBody(resource);
                         exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_CRD_EVENT_ACTION, action);
                         exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_CRD_EVENT_TIMESTAMP,
@@ -106,6 +106,8 @@ public class KubernetesCustomResourcesConsumer extends DefaultConsumer {
                             processor.process(exchange);
                         } catch (Exception e) {
                             getExceptionHandler().handleException("Error during processing", exchange, e);
+                        } finally {
+                            releaseExchange(exchange, false);
                         }
                     }
 
diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsConsumer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsConsumer.java
index 58bbc45..5eed4b8 100644
--- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsConsumer.java
+++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsConsumer.java
@@ -105,7 +105,7 @@ public class KubernetesDeploymentsConsumer extends DefaultConsumer {
                 @Override
                 public void eventReceived(io.fabric8.kubernetes.client.Watcher.Action action, Deployment resource) {
                     DeploymentEvent de = new DeploymentEvent(action, resource);
-                    Exchange exchange = getEndpoint().createExchange();
+                    Exchange exchange = createExchange(false);
                     exchange.getIn().setBody(de.getDeployment());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_ACTION, de.getAction());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_TIMESTAMP, System.currentTimeMillis());
@@ -113,6 +113,8 @@ public class KubernetesDeploymentsConsumer extends DefaultConsumer {
                         processor.process(exchange);
                     } catch (Exception e) {
                         getExceptionHandler().handleException("Error during processing", exchange, e);
+                    } finally {
+                        releaseExchange(exchange, false);
                     }
                 }
 
diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/hpa/KubernetesHPAConsumer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/hpa/KubernetesHPAConsumer.java
index 99d13e5..abf7d09 100644
--- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/hpa/KubernetesHPAConsumer.java
+++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/hpa/KubernetesHPAConsumer.java
@@ -109,7 +109,7 @@ public class KubernetesHPAConsumer extends DefaultConsumer {
                 public void eventReceived(
                         io.fabric8.kubernetes.client.Watcher.Action action, HorizontalPodAutoscaler resource) {
                     HPAEvent hpae = new HPAEvent(action, resource);
-                    Exchange exchange = getEndpoint().createExchange();
+                    Exchange exchange = createExchange(false);
                     exchange.getIn().setBody(hpae.getHpa());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_ACTION, hpae.getAction());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_TIMESTAMP, System.currentTimeMillis());
@@ -117,6 +117,8 @@ public class KubernetesHPAConsumer extends DefaultConsumer {
                         processor.process(exchange);
                     } catch (Exception e) {
                         getExceptionHandler().handleException("Error during processing", exchange, e);
+                    } finally {
+                        releaseExchange(exchange, false);
                     }
                 }
 
diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/namespaces/KubernetesNamespacesConsumer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/namespaces/KubernetesNamespacesConsumer.java
index 862fe83..aa026f7 100644
--- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/namespaces/KubernetesNamespacesConsumer.java
+++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/namespaces/KubernetesNamespacesConsumer.java
@@ -99,7 +99,7 @@ public class KubernetesNamespacesConsumer extends DefaultConsumer {
                 @Override
                 public void eventReceived(io.fabric8.kubernetes.client.Watcher.Action action, Namespace resource) {
                     NamespaceEvent ne = new NamespaceEvent(action, resource);
-                    Exchange exchange = getEndpoint().createExchange();
+                    Exchange exchange = createExchange(false);
                     exchange.getIn().setBody(ne.getNamespace());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_ACTION, ne.getAction());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_TIMESTAMP, System.currentTimeMillis());
@@ -107,6 +107,8 @@ public class KubernetesNamespacesConsumer extends DefaultConsumer {
                         processor.process(exchange);
                     } catch (Exception e) {
                         getExceptionHandler().handleException("Error during processing", exchange, e);
+                    } finally {
+                        releaseExchange(exchange, false);
                     }
                 }
 
diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/nodes/KubernetesNodesConsumer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/nodes/KubernetesNodesConsumer.java
index 0a4f745..651eeee 100644
--- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/nodes/KubernetesNodesConsumer.java
+++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/nodes/KubernetesNodesConsumer.java
@@ -103,7 +103,7 @@ public class KubernetesNodesConsumer extends DefaultConsumer {
                 @Override
                 public void eventReceived(io.fabric8.kubernetes.client.Watcher.Action action, Node resource) {
                     NodeEvent ne = new NodeEvent(action, resource);
-                    Exchange exchange = getEndpoint().createExchange();
+                    Exchange exchange = createExchange(false);
                     exchange.getIn().setBody(ne.getNode());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_ACTION, ne.getAction());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_TIMESTAMP, System.currentTimeMillis());
@@ -111,6 +111,8 @@ public class KubernetesNodesConsumer extends DefaultConsumer {
                         processor.process(exchange);
                     } catch (Exception e) {
                         getExceptionHandler().handleException("Error during processing", exchange, e);
+                    } finally {
+                        releaseExchange(exchange, false);
                     }
                 }
 
diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/pods/KubernetesPodsConsumer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/pods/KubernetesPodsConsumer.java
index d336aef..5f7b071 100644
--- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/pods/KubernetesPodsConsumer.java
+++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/pods/KubernetesPodsConsumer.java
@@ -106,7 +106,7 @@ public class KubernetesPodsConsumer extends DefaultConsumer {
                 @Override
                 public void eventReceived(io.fabric8.kubernetes.client.Watcher.Action action, Pod resource) {
                     PodEvent pe = new PodEvent(action, resource);
-                    Exchange exchange = getEndpoint().createExchange();
+                    Exchange exchange = createExchange(false);
                     exchange.getIn().setBody(pe.getPod());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_ACTION, pe.getAction());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_TIMESTAMP, System.currentTimeMillis());
@@ -114,6 +114,8 @@ public class KubernetesPodsConsumer extends DefaultConsumer {
                         processor.process(exchange);
                     } catch (Exception e) {
                         getExceptionHandler().handleException("Error during processing", exchange, e);
+                    } finally {
+                        releaseExchange(exchange, false);
                     }
                 }
 
diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/replication_controllers/KubernetesReplicationControllersConsumer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/replication_controllers/KubernetesReplicationControllersConsumer.java
index a2a0d8d..8aec7d8 100644
--- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/replication_controllers/KubernetesReplicationControllersConsumer.java
+++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/replication_controllers/KubernetesReplicationControllersConsumer.java
@@ -108,7 +108,7 @@ public class KubernetesReplicationControllersConsumer extends DefaultConsumer {
                 @Override
                 public void eventReceived(io.fabric8.kubernetes.client.Watcher.Action action, ReplicationController resource) {
                     ReplicationControllerEvent rce = new ReplicationControllerEvent(action, resource);
-                    Exchange exchange = getEndpoint().createExchange();
+                    Exchange exchange = createExchange(false);
                     exchange.getIn().setBody(rce.getReplicationController());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_ACTION, rce.getAction());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_TIMESTAMP, System.currentTimeMillis());
@@ -116,8 +116,9 @@ public class KubernetesReplicationControllersConsumer extends DefaultConsumer {
                         processor.process(exchange);
                     } catch (Exception e) {
                         getExceptionHandler().handleException("Error during processing", exchange, e);
+                    } finally {
+                        releaseExchange(exchange, false);
                     }
-
                 }
 
                 @Override
diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/services/KubernetesServicesConsumer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/services/KubernetesServicesConsumer.java
index 98b3cb0..3b78fe8 100644
--- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/services/KubernetesServicesConsumer.java
+++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/services/KubernetesServicesConsumer.java
@@ -106,7 +106,7 @@ public class KubernetesServicesConsumer extends DefaultConsumer {
                 @Override
                 public void eventReceived(io.fabric8.kubernetes.client.Watcher.Action action, Service resource) {
                     ServiceEvent se = new ServiceEvent(action, resource);
-                    Exchange exchange = getEndpoint().createExchange();
+                    Exchange exchange = createExchange(false);
                     exchange.getIn().setBody(se.getService());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_ACTION, se.getAction());
                     exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_TIMESTAMP, System.currentTimeMillis());
@@ -114,8 +114,9 @@ public class KubernetesServicesConsumer extends DefaultConsumer {
                         processor.process(exchange);
                     } catch (Exception e) {
                         getExceptionHandler().handleException("Error during processing", exchange, e);
+                    } finally {
+                        releaseExchange(exchange, false);
                     }
-
                 }
 
                 @Override
diff --git a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
index dd541b2..6fe7825 100644
--- a/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
+++ b/components/camel-mail/src/main/java/org/apache/camel/component/mail/MailConsumer.java
@@ -385,7 +385,7 @@ public class MailConsumer extends ScheduledBatchPollingConsumer {
                 }
 
                 if (!message.getFlags().contains(Flags.Flag.DELETED)) {
-                    Exchange exchange = getEndpoint().createExchange(message);
+                    Exchange exchange = createExchange(message);
                     if (getEndpoint().getConfiguration().isMapMailMessage()) {
                         // ensure the mail message is mapped, which can be ensured by touching the body/header/attachment
                         LOG.trace("Mapping #{} from javax.mail.Message to Camel MailMessage", i);
@@ -399,6 +399,8 @@ public class MailConsumer extends ScheduledBatchPollingConsumer {
                                 exchange.getIn(AttachmentMessage.class).setAttachmentObjects(att);
                             }
                         } catch (MessagingException | IOException e) {
+                            // must release exchange before throwing exception
+                            releaseExchange(exchange, true);
                             throw new RuntimeCamelException("Error accessing attachments due to: " + e.getMessage(), e);
                         }
                     }
@@ -511,6 +513,13 @@ public class MailConsumer extends ScheduledBatchPollingConsumer {
         }
     }
 
+    private Exchange createExchange(Message message) {
+        Exchange exchange = createExchange(true);
+        exchange.setProperty(Exchange.BINDING, getEndpoint().getBinding());
+        exchange.setIn(new MailMessage(exchange, message, getEndpoint().getConfiguration().isMapMailMessage()));
+        return exchange;
+    }
+
     private void copyOrMoveMessageIfRequired(
             MailConfiguration config, Message mail, String destinationFolder, boolean moveMessage)
             throws MessagingException {
diff --git a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailConsumerAuthenticatorTest.java b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailConsumerAuthenticatorTest.java
index e4ea961..c4f18a7 100644
--- a/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailConsumerAuthenticatorTest.java
+++ b/components/camel-mail/src/test/java/org/apache/camel/component/mail/MailConsumerAuthenticatorTest.java
@@ -23,12 +23,15 @@ import javax.mail.MessagingException;
 import javax.mail.PasswordAuthentication;
 import javax.mail.Session;
 
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Processor;
+import org.apache.camel.spi.ExchangeFactory;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.when;
 
 /**
@@ -51,8 +54,11 @@ public class MailConsumerAuthenticatorTest {
 
         JavaMailSender sender = Mockito.mock(JavaMailSender.class);
         Processor processor = Mockito.mock(Processor.class);
+        ExtendedCamelContext ecc = Mockito.mock(ExtendedCamelContext.class);
+        ExchangeFactory ef = Mockito.mock(ExchangeFactory.class);
 
         MailEndpoint endpoint = new MailEndpoint();
+        endpoint.setCamelContext(ecc);
         MailConfiguration configuration = new MailConfiguration();
         configuration.setAuthenticator(authenticator);
         configuration.configureProtocol(protocol);
@@ -65,6 +71,9 @@ public class MailConsumerAuthenticatorTest {
         Session session = Session.getDefaultInstance(props, authenticator);
 
         when(sender.getSession()).thenReturn(session);
+        when(ecc.adapt(ExtendedCamelContext.class)).thenReturn(ecc);
+        when(ecc.getExchangeFactory()).thenReturn(ef);
+        when(ef.newExchangeFactory(any())).thenReturn(ef);
 
         MailConsumer consumer = new MailConsumer(endpoint, processor, sender);
         try {
diff --git a/components/camel-master/src/test/java/org/apache/camel/component/master/EndpointUriEncodingTest.java b/components/camel-master/src/test/java/org/apache/camel/component/master/EndpointUriEncodingTest.java
index 37c701c..c78a06c 100644
--- a/components/camel-master/src/test/java/org/apache/camel/component/master/EndpointUriEncodingTest.java
+++ b/components/camel-master/src/test/java/org/apache/camel/component/master/EndpointUriEncodingTest.java
@@ -86,7 +86,7 @@ public class EndpointUriEncodingTest extends CamelTestSupport {
                     return new DefaultConsumer(this, processor) {
                         @Override
                         public void start() {
-                            Exchange exchange = createExchange();
+                            Exchange exchange = createExchange(true);
                             exchange.getMessage().setHeader("foo", foo);
                             exchange.getMessage().setHeader("bar", bar);
                             try {
diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConsumer.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConsumer.java
index 408af8c..6068910 100644
--- a/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConsumer.java
+++ b/components/camel-milo/src/main/java/org/apache/camel/component/milo/client/MiloClientConsumer.java
@@ -69,10 +69,9 @@ public class MiloClientConsumer extends DefaultConsumer {
     private void handleValueUpdate(final DataValue value) {
         LOG.debug("Handle item update - {} = {}", node, value);
 
-        final Exchange exchange = getEndpoint().createExchange();
-        mapToMessage(value, exchange.getMessage());
-
+        final Exchange exchange = createExchange(true);
         try {
+            mapToMessage(value, exchange.getMessage());
             getProcessor().process(exchange);
         } catch (final Exception e) {
             getExceptionHandler().handleException("Error processing exchange", e);
diff --git a/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/MiloServerConsumer.java b/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/MiloServerConsumer.java
index f958974..7677e17 100644
--- a/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/MiloServerConsumer.java
+++ b/components/camel-milo/src/main/java/org/apache/camel/component/milo/server/MiloServerConsumer.java
@@ -54,10 +54,10 @@ public class MiloServerConsumer extends DefaultConsumer {
     }
 
     protected void performWrite(final DataValue value) {
-        Exchange exchange = getEndpoint().createExchange();
-        mapToMessage(value, exchange.getMessage());
+        Exchange exchange = createExchange(true);
 
         try {
+            mapToMessage(value, exchange.getMessage());
             getProcessor().process(exchange);
         } catch (Exception e) {
             getExceptionHandler().handleException("Error processing exchange", e);
diff --git a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConsumer.java b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConsumer.java
index 1152f8f..76917e3 100644
--- a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConsumer.java
+++ b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaConsumer.java
@@ -373,6 +373,21 @@ public class MinaConsumer extends DefaultConsumer {
         this.acceptor = acceptor;
     }
 
+    private Exchange createExchange(IoSession session, Object payload) {
+        Exchange exchange;
+        if (configuration.isTransferExchange()) {
+            // do not release
+            exchange = getEndpoint().createExchange();
+        } else {
+            exchange = createExchange(false);
+        }
+        exchange.getIn().setHeader(MinaConstants.MINA_IOSESSION, session);
+        exchange.getIn().setHeader(MinaConstants.MINA_LOCAL_ADDRESS, session.getLocalAddress());
+        exchange.getIn().setHeader(MinaConstants.MINA_REMOTE_ADDRESS, session.getRemoteAddress());
+        MinaPayloadHelper.setIn(exchange, payload);
+        return exchange;
+    }
+
     /**
      * Handles consuming messages and replying if the exchange is out capable.
      */
@@ -406,7 +421,7 @@ public class MinaConsumer extends DefaultConsumer {
                 LOG.debug("Received body: {}", in);
             }
 
-            Exchange exchange = getEndpoint().createExchange(session, object);
+            Exchange exchange = createExchange(session, object);
             //Set the exchange charset property for converting
             if (getEndpoint().getConfiguration().getCharsetName() != null) {
                 exchange.setProperty(Exchange.CHARSET_NAME,
@@ -419,50 +434,54 @@ public class MinaConsumer extends DefaultConsumer {
                 getExceptionHandler().handleException(e);
             }
 
-            //
-            // If there's a response to send, send it.
-            //
-            boolean disconnect = getEndpoint().getConfiguration().isDisconnect();
-            Object response = null;
-            if (exchange.hasOut()) {
-                response = MinaPayloadHelper.getOut(getEndpoint(), exchange);
-            } else {
-                response = MinaPayloadHelper.getIn(getEndpoint(), exchange);
-            }
-
-            boolean failed = exchange.isFailed();
-            if (failed && !getEndpoint().getConfiguration().isTransferExchange()) {
-                if (exchange.getException() != null) {
-                    response = exchange.getException();
+            try {
+                //
+                // If there's a response to send, send it.
+                //
+                boolean disconnect = getEndpoint().getConfiguration().isDisconnect();
+                Object response;
+                if (exchange.hasOut()) {
+                    response = MinaPayloadHelper.getOut(getEndpoint(), exchange);
                 } else {
-                    // failed and no exception, must be a fault
-                    response = exchange.getOut().getBody();
+                    response = MinaPayloadHelper.getIn(getEndpoint(), exchange);
                 }
-            }
 
-            if (response != null) {
-                LOG.debug("Writing body: {}", response);
-                MinaHelper.writeBody(session, response, exchange, configuration.getWriteTimeout());
-            } else {
-                LOG.debug("Writing no response");
-                disconnect = Boolean.TRUE;
-            }
+                boolean failed = exchange.isFailed();
+                if (failed && !getEndpoint().getConfiguration().isTransferExchange()) {
+                    if (exchange.getException() != null) {
+                        response = exchange.getException();
+                    } else {
+                        // failed and no exception, must be a fault
+                        response = exchange.getOut().getBody();
+                    }
+                }
 
-            // should session be closed after complete?
-            Boolean close;
-            if (ExchangeHelper.isOutCapable(exchange)) {
-                close = exchange.getOut().getHeader(MinaConstants.MINA_CLOSE_SESSION_WHEN_COMPLETE, Boolean.class);
-            } else {
-                close = exchange.getIn().getHeader(MinaConstants.MINA_CLOSE_SESSION_WHEN_COMPLETE, Boolean.class);
-            }
+                if (response != null) {
+                    LOG.debug("Writing body: {}", response);
+                    MinaHelper.writeBody(session, response, exchange, configuration.getWriteTimeout());
+                } else {
+                    LOG.debug("Writing no response");
+                    disconnect = Boolean.TRUE;
+                }
 
-            // should we disconnect, the header can override the configuration
-            if (close != null) {
-                disconnect = close;
-            }
-            if (disconnect) {
-                LOG.debug("Closing session when complete at address: {}", address);
-                session.closeNow();
+                // should session be closed after complete?
+                Boolean close;
+                if (ExchangeHelper.isOutCapable(exchange)) {
+                    close = exchange.getOut().getHeader(MinaConstants.MINA_CLOSE_SESSION_WHEN_COMPLETE, Boolean.class);
+                } else {
+                    close = exchange.getIn().getHeader(MinaConstants.MINA_CLOSE_SESSION_WHEN_COMPLETE, Boolean.class);
+                }
+
+                // should we disconnect, the header can override the configuration
+                if (close != null) {
+                    disconnect = close;
+                }
+                if (disconnect) {
+                    LOG.debug("Closing session when complete at address: {}", address);
+                    session.closeNow();
+                }
+            } finally {
+                releaseExchange(exchange, false);
             }
         }
     }
diff --git a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaEndpoint.java b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaEndpoint.java
index 2d3784a..416579a 100644
--- a/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaEndpoint.java
+++ b/components/camel-mina/src/main/java/org/apache/camel/component/mina/MinaEndpoint.java
@@ -19,7 +19,6 @@ package org.apache.camel.component.mina;
 import org.apache.camel.Category;
 import org.apache.camel.Component;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
 import org.apache.camel.MultipleConsumersSupport;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
@@ -27,7 +26,6 @@ import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.support.DefaultEndpoint;
 import org.apache.camel.util.ObjectHelper;
-import org.apache.mina.core.session.IoSession;
 
 /**
  * Socket level networking using TCP or UDP with Apache Mina 2.x.
@@ -68,15 +66,6 @@ public class MinaEndpoint extends DefaultEndpoint implements MultipleConsumersSu
         return answer;
     }
 
-    public Exchange createExchange(IoSession session, Object payload) {
-        Exchange exchange = createExchange();
-        exchange.getIn().setHeader(MinaConstants.MINA_IOSESSION, session);
-        exchange.getIn().setHeader(MinaConstants.MINA_LOCAL_ADDRESS, session.getLocalAddress());
-        exchange.getIn().setHeader(MinaConstants.MINA_REMOTE_ADDRESS, session.getRemoteAddress());
-        MinaPayloadHelper.setIn(exchange, payload);
-        return exchange;
-    }
-
     @Override
     public boolean isMultipleConsumersSupported() {
         // only datagram should allow multiple consumers
diff --git a/components/camel-mina/src/test/java/org/apache/camel/component/mina/MinaTransferExchangeOptionTest.java b/components/camel-mina/src/test/java/org/apache/camel/component/mina/MinaTransferExchangeOptionTest.java
index c0354ae..140617b 100644
--- a/components/camel-mina/src/test/java/org/apache/camel/component/mina/MinaTransferExchangeOptionTest.java
+++ b/components/camel-mina/src/test/java/org/apache/camel/component/mina/MinaTransferExchangeOptionTest.java
@@ -58,7 +58,6 @@ public class MinaTransferExchangeOptionTest extends BaseMinaTest {
                 String.format("mina:tcp://localhost:%1$s?sync=true&encoding=UTF-8&transferExchange=true", getPort()));
         Producer producer = endpoint.createProducer();
         Exchange exchange = endpoint.createExchange();
-        //Exchange exchange = endpoint.createExchange();
 
         Message message = exchange.getIn();
         message.setBody("Hello!");
diff --git a/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioConsumer.java b/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioConsumer.java
index df0a7d9..e98b295 100644
--- a/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioConsumer.java
+++ b/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioConsumer.java
@@ -39,9 +39,11 @@ import io.minio.errors.MinioException;
 import io.minio.messages.Item;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExtendedExchange;
+import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.spi.Synchronization;
 import org.apache.camel.support.ScheduledBatchPollingConsumer;
+import org.apache.camel.support.SynchronizationAdapter;
 import org.apache.camel.util.CastUtils;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.URISupport;
@@ -182,7 +184,7 @@ public class MinioConsumer extends ScheduledBatchPollingConsumer {
 
     protected Queue<Exchange> createExchanges(InputStream objectStream, String objectName) throws Exception {
         Queue<Exchange> answer = new LinkedList<>();
-        Exchange exchange = getEndpoint().createExchange(objectStream, objectName);
+        Exchange exchange = createExchange(objectStream, objectName);
         answer.add(exchange);
         IOHelper.close(objectStream);
         return answer;
@@ -200,7 +202,7 @@ public class MinioConsumer extends ScheduledBatchPollingConsumer {
                     Item minioObjectSummary = minioObjectSummaries.next().get();
                     InputStream minioObject = getObject(bucketName, getMinioClient(), minioObjectSummary.objectName());
                     minioObjects.add(minioObject);
-                    Exchange exchange = getEndpoint().createExchange(minioObject, minioObjectSummary.objectName());
+                    Exchange exchange = createExchange(minioObject, minioObjectSummary.objectName());
                     answer.add(exchange);
                     continuationToken = minioObjectSummary.objectName();
                 } while (minioObjectSummaries.hasNext());
@@ -212,7 +214,7 @@ public class MinioConsumer extends ScheduledBatchPollingConsumer {
                     if (!minioObjectSummary.isDir()) {
                         InputStream minioObject = getObject(bucketName, getMinioClient(), minioObjectSummary.objectName());
                         minioObjects.add(minioObject);
-                        Exchange exchange = getEndpoint().createExchange(minioObject, minioObjectSummary.objectName());
+                        Exchange exchange = createExchange(minioObject, minioObjectSummary.objectName());
                         answer.add(exchange);
                         continuationToken = minioObjectSummary.objectName();
                     }
@@ -401,6 +403,34 @@ public class MinioConsumer extends ScheduledBatchPollingConsumer {
         return (MinioEndpoint) super.getEndpoint();
     }
 
+    private Exchange createExchange(InputStream minioObject, String objectName) throws Exception {
+        LOG.trace("Getting object with objectName {} from bucket {}...", objectName, getConfiguration().getBucketName());
+
+        Exchange exchange = createExchange(true);
+        exchange.setPattern(getEndpoint().getExchangePattern());
+        Message message = exchange.getIn();
+        LOG.trace("Got object!");
+
+        getEndpoint().getObjectStat(objectName, message);
+
+        if (getConfiguration().isIncludeBody()) {
+            message.setBody(getEndpoint().readInputStream(minioObject));
+            if (getConfiguration().isAutoCloseBody()) {
+                exchange.adapt(ExtendedExchange.class).addOnCompletion(new SynchronizationAdapter() {
+                    @Override
+                    public void onDone(Exchange exchange) {
+                        IOHelper.close(minioObject);
+                    }
+                });
+            }
+        } else {
+            message.setBody(null);
+            IOHelper.close(minioObject);
+        }
+
+        return exchange;
+    }
+
     @Override
     public String toString() {
         if (isEmpty(minioConsumerToString)) {
diff --git a/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioEndpoint.java b/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioEndpoint.java
index e85cf8f..bb67186 100644
--- a/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioEndpoint.java
+++ b/components/camel-minio/src/main/java/org/apache/camel/component/minio/MinioEndpoint.java
@@ -32,17 +32,12 @@ import io.minio.StatObjectResponse;
 import org.apache.camel.Category;
 import org.apache.camel.Component;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.ExtendedExchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.support.ScheduledPollEndpoint;
-import org.apache.camel.support.SynchronizationAdapter;
-import org.apache.camel.util.IOHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -123,37 +118,6 @@ public class MinioEndpoint extends ScheduledPollEndpoint {
         super.doStop();
     }
 
-    public Exchange createExchange(InputStream minioObject, String objectName) throws Exception {
-        return createExchange(getExchangePattern(), minioObject, objectName);
-    }
-
-    public Exchange createExchange(ExchangePattern pattern, InputStream minioObject, String objectName) throws Exception {
-        LOG.trace("Getting object with objectName {} from bucket {}...", objectName, getConfiguration().getBucketName());
-
-        Exchange exchange = super.createExchange(pattern);
-        Message message = exchange.getIn();
-        LOG.trace("Got object!");
-
-        getObjectStat(objectName, message);
-
-        if (getConfiguration().isIncludeBody()) {
-            message.setBody(readInputStream(minioObject));
-            if (getConfiguration().isAutoCloseBody()) {
-                exchange.adapt(ExtendedExchange.class).addOnCompletion(new SynchronizationAdapter() {
-                    @Override
-                    public void onDone(Exchange exchange) {
-                        IOHelper.close(minioObject);
-                    }
-                });
-            }
-        } else {
-            message.setBody(null);
-            IOHelper.close(minioObject);
-        }
-
-        return exchange;
-    }
-
     public MinioConfiguration getConfiguration() {
         return configuration;
     }
@@ -196,7 +160,7 @@ public class MinioEndpoint extends ScheduledPollEndpoint {
         }
     }
 
-    private String readInputStream(InputStream minioObject) throws IOException {
+    String readInputStream(InputStream minioObject) throws IOException {
         StringBuilder textBuilder = new StringBuilder();
         try (Reader reader = new BufferedReader(new InputStreamReader(minioObject, StandardCharsets.UTF_8))) {
             int c;
@@ -227,7 +191,7 @@ public class MinioEndpoint extends ScheduledPollEndpoint {
         LOG.trace("Bucket policy updated");
     }
 
-    private void getObjectStat(String objectName, Message message) throws Exception {
+    void getObjectStat(String objectName, Message message) throws Exception {
 
         String bucketName = getConfiguration().getBucketName();
         StatObjectArgs.Builder statObjectRequest = StatObjectArgs.builder().bucket(bucketName).object(objectName);
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
index d1e3a4a..35719f0 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
@@ -109,7 +109,7 @@ public class MllpEndpoint extends DefaultEndpoint {
         super.setBridgeErrorHandler(configuration.isBridgeErrorHandler());
     }
 
-    private void setExchangeProperties(Exchange mllpExchange) {
+    void setExchangeProperties(Exchange mllpExchange) {
         if (configuration.hasCharsetName()) {
             mllpExchange.setProperty(Exchange.CHARSET_NAME, configuration.getCharsetName());
         }
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
index d43c356..2ca75bb 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
@@ -228,7 +228,8 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
         // Send the message on to Camel for processing and wait for the response
         log.debug("processMessage(hl7MessageBytes[{}], {}) - populating the exchange with received payload",
                 hl7MessageBytes == null ? -1 : hl7MessageBytes.length, consumerRunnable.getSocket());
-        Exchange exchange = getEndpoint().createExchange(ExchangePattern.InOut);
+        Exchange exchange = createExchange(false);
+        exchange.setPattern(ExchangePattern.InOut);
         if (getConfiguration().hasCharsetName()) {
             exchange.setProperty(Exchange.CHARSET_NAME, getConfiguration().getCharsetName());
         }
@@ -283,9 +284,8 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
                     "processMessage(byte[], TcpSocketConsumerRunnable) - Unexpected exception creating Unit of Work", exchange,
                     uowEx);
         } finally {
-            if (exchange != null) {
-                doneUoW(exchange);
-            }
+            doneUoW(exchange);
+            releaseExchange(exchange, false);
         }
     }
 
diff --git a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java
index 9ffb2df..10d2c81 100644
--- a/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java
+++ b/components/camel-mock/src/main/java/org/apache/camel/component/mock/MockEndpoint.java
@@ -144,12 +144,12 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
     private boolean copyOnExchange = true;
 
     public MockEndpoint() {
-        init();
+        reset();
     }
 
     public MockEndpoint(String endpointUri, Component component) {
         super(endpointUri, component);
-        init();
+        reset();
     }
 
     /**
@@ -308,7 +308,28 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
     }
 
     public void reset() {
-        doInit();
+        expectedCount = -1;
+        counter = 0;
+        defaultProcessor = null;
+        processors = new HashMap<>();
+        receivedExchanges = new CopyOnWriteArrayList<>();
+        failures = new CopyOnWriteArrayList<>();
+        tests = new CopyOnWriteArrayList<>();
+        latch = null;
+        failFastAssertionError = null;
+        sleepForEmptyTest = 0;
+        resultWaitTime = 0;
+        resultMinimumWaitTime = 0L;
+        assertPeriod = 0L;
+        expectedMinimumCount = -1;
+        expectedBodyValues = null;
+        actualBodyValues = new ArrayList<>();
+        expectedHeaderValues = null;
+        actualHeaderValues = null;
+        expectedPropertyValues = null;
+        actualPropertyValues = null;
+        retainFirst = -1;
+        retainLast = -1;
     }
 
     // Testing API
@@ -1516,31 +1537,6 @@ public class MockEndpoint extends DefaultEndpoint implements BrowsableEndpoint,
 
     // Implementation methods
     // -------------------------------------------------------------------------
-    @Override
-    protected void doInit() {
-        expectedCount = -1;
-        counter = 0;
-        defaultProcessor = null;
-        processors = new HashMap<>();
-        receivedExchanges = new CopyOnWriteArrayList<>();
-        failures = new CopyOnWriteArrayList<>();
-        tests = new CopyOnWriteArrayList<>();
-        latch = null;
-        failFastAssertionError = null;
-        sleepForEmptyTest = 0;
-        resultWaitTime = 0;
-        resultMinimumWaitTime = 0L;
-        assertPeriod = 0L;
-        expectedMinimumCount = -1;
-        expectedBodyValues = null;
-        actualBodyValues = new ArrayList<>();
-        expectedHeaderValues = null;
-        actualHeaderValues = null;
-        expectedPropertyValues = null;
-        actualPropertyValues = null;
-        retainFirst = -1;
-        retainLast = -1;
-    }
 
     protected synchronized void onExchange(Exchange exchange) {
         try {
diff --git a/components/camel-mongodb-gridfs/src/main/java/org/apache/camel/component/mongodb/gridfs/GridFsConsumer.java b/components/camel-mongodb-gridfs/src/main/java/org/apache/camel/component/mongodb/gridfs/GridFsConsumer.java
index 60eff1d..74fe66a 100644
--- a/components/camel-mongodb-gridfs/src/main/java/org/apache/camel/component/mongodb/gridfs/GridFsConsumer.java
+++ b/components/camel-mongodb-gridfs/src/main/java/org/apache/camel/component/mongodb/gridfs/GridFsConsumer.java
@@ -142,7 +142,7 @@ public class GridFsConsumer extends DefaultConsumer implements Runnable {
                         forig = endpoint.getFilesCollection().findOneAndUpdate(filter, update, options);
                     }
                     if (forig != null) {
-                        Exchange exchange = endpoint.createExchange();
+                        Exchange exchange = createExchange(true);
                         GridFSDownloadStream downloadStream = endpoint.getGridFsBucket().openDownloadStream(file.getFilename());
                         file = downloadStream.getGridFSFile();
 
diff --git a/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbChangeStreamsConsumer.java b/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbChangeStreamsConsumer.java
index f625205..62cf9bb 100644
--- a/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbChangeStreamsConsumer.java
+++ b/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbChangeStreamsConsumer.java
@@ -69,4 +69,5 @@ public class MongoDbChangeStreamsConsumer extends DefaultConsumer {
         changeStreamsThread.init();
         executor.execute(changeStreamsThread);
     }
+
 }
diff --git a/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbChangeStreamsThread.java b/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbChangeStreamsThread.java
index 116b072..8757793 100644
--- a/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbChangeStreamsThread.java
+++ b/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbChangeStreamsThread.java
@@ -24,6 +24,7 @@ import com.mongodb.client.MongoCursor;
 import com.mongodb.client.model.changestream.ChangeStreamDocument;
 import com.mongodb.client.model.changestream.OperationType;
 import org.apache.camel.Exchange;
+import org.apache.camel.Message;
 import org.bson.BsonDocument;
 import org.bson.Document;
 import org.bson.types.ObjectId;
@@ -70,7 +71,7 @@ class MongoDbChangeStreamsThread extends MongoAbstractConsumerThread {
         try {
             while (cursor.hasNext() && keepRunning) {
                 ChangeStreamDocument<Document> dbObj = (ChangeStreamDocument<Document>) cursor.next();
-                Exchange exchange = endpoint.createMongoDbExchange(dbObj.getFullDocument());
+                Exchange exchange = createMongoDbExchange(dbObj.getFullDocument());
 
                 ObjectId documentId = dbObj.getDocumentKey().getObjectId(MONGO_ID).getValue();
                 OperationType operationType = dbObj.getOperationType();
@@ -101,4 +102,15 @@ class MongoDbChangeStreamsThread extends MongoAbstractConsumerThread {
             }
         }
     }
+
+    private Exchange createMongoDbExchange(Document dbObj) {
+        Exchange exchange = consumer.createExchange(true);
+        Message message = exchange.getIn();
+        message.setHeader(MongoDbConstants.DATABASE, endpoint.getDatabase());
+        message.setHeader(MongoDbConstants.COLLECTION, endpoint.getCollection());
+        message.setHeader(MongoDbConstants.FROM_TAILABLE, true);
+        message.setBody(dbObj);
+        return exchange;
+    }
+
 }
diff --git a/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbEndpoint.java b/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbEndpoint.java
index 76ddc9a..a118fea 100644
--- a/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbEndpoint.java
+++ b/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbEndpoint.java
@@ -31,8 +31,6 @@ import com.mongodb.client.MongoCollection;
 import com.mongodb.client.MongoDatabase;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.spi.Metadata;
@@ -318,16 +316,6 @@ public class MongoDbEndpoint extends DefaultEndpoint {
         }
     }
 
-    public Exchange createMongoDbExchange(Document dbObj) {
-        Exchange exchange = super.createExchange();
-        Message message = exchange.getIn();
-        message.setHeader(MongoDbConstants.DATABASE, database);
-        message.setHeader(MongoDbConstants.COLLECTION, collection);
-        message.setHeader(MongoDbConstants.FROM_TAILABLE, true);
-        message.setBody(dbObj);
-        return exchange;
-    }
-
     @Override
     protected void doStart() throws Exception {
         if (mongoConnection == null) {
diff --git a/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbTailingThread.java b/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbTailingThread.java
index 5f870d1..b2c7747 100644
--- a/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbTailingThread.java
+++ b/components/camel-mongodb/src/main/java/org/apache/camel/component/mongodb/MongoDbTailingThread.java
@@ -20,6 +20,7 @@ import com.mongodb.CursorType;
 import com.mongodb.MongoCursorNotFoundException;
 import com.mongodb.client.MongoCursor;
 import org.apache.camel.Exchange;
+import org.apache.camel.Message;
 import org.bson.Document;
 
 import static com.mongodb.client.model.Filters.gt;
@@ -110,7 +111,7 @@ class MongoDbTailingThread extends MongoAbstractConsumerThread {
         try {
             while (cursor.hasNext() && keepRunning) {
                 Document dbObj = (Document) cursor.next();
-                Exchange exchange = endpoint.createMongoDbExchange(dbObj);
+                Exchange exchange = createMongoDbExchange(dbObj);
                 try {
                     if (log.isTraceEnabled()) {
                         log.trace("Sending exchange: {}, ObjectId: {}", exchange, dbObj.get(MONGO_ID));
@@ -145,4 +146,15 @@ class MongoDbTailingThread extends MongoAbstractConsumerThread {
             tailTracking.persistToStore();
         }
     }
+
+    Exchange createMongoDbExchange(Document dbObj) {
+        Exchange exchange = consumer.createExchange(true);
+        Message message = exchange.getIn();
+        message.setHeader(MongoDbConstants.DATABASE, endpoint.getDatabase());
+        message.setHeader(MongoDbConstants.COLLECTION, endpoint.getCollection());
+        message.setHeader(MongoDbConstants.FROM_TAILABLE, true);
+        message.setBody(dbObj);
+        return exchange;
+    }
+
 }
diff --git a/components/camel-mybatis/src/main/java/org/apache/camel/component/mybatis/MyBatisConsumer.java b/components/camel-mybatis/src/main/java/org/apache/camel/component/mybatis/MyBatisConsumer.java
index 45bfca1..bfc721d 100644
--- a/components/camel-mybatis/src/main/java/org/apache/camel/component/mybatis/MyBatisConsumer.java
+++ b/components/camel-mybatis/src/main/java/org/apache/camel/component/mybatis/MyBatisConsumer.java
@@ -130,9 +130,10 @@ public class MyBatisConsumer extends ScheduledBatchPollingConsumer {
 
             // process the current exchange
             LOG.debug("Processing exchange: {} with properties: {}", exchange, exchange.getProperties());
-            getProcessor().process(exchange);
-
+            Exception cause = null;
             try {
+                getProcessor().process(exchange);
+
                 if (onConsume != null) {
                     endpoint.getProcessingStrategy().commit(endpoint, exchange, data, onConsume);
                 }
@@ -142,13 +143,16 @@ public class MyBatisConsumer extends ScheduledBatchPollingConsumer {
 
             if (getEndpoint().isTransacted() && exchange.isFailed()) {
                 // break out as we are transacted and should rollback
-                Exception cause = exchange.getException();
-                if (cause != null) {
-                    throw cause;
-                } else {
-                    throw new RollbackExchangeException("Rollback transaction due error processing exchange", exchange);
+                cause = exchange.getException();
+                if (cause == null) {
+                    cause = new RollbackExchangeException("Rollback transaction due error processing exchange", null);
                 }
             }
+            releaseExchange(exchange, false);
+
+            if (cause != null) {
+                throw cause;
+            }
         }
 
         return total;
@@ -156,7 +160,8 @@ public class MyBatisConsumer extends ScheduledBatchPollingConsumer {
 
     private Exchange createExchange(Object data) {
         final MyBatisEndpoint endpoint = getEndpoint();
-        final Exchange exchange = endpoint.createExchange(ExchangePattern.InOnly);
+        final Exchange exchange = createExchange(false);
+        exchange.setPattern(ExchangePattern.InOnly);
         final String outputHeader = getEndpoint().getOutputHeader();
 
         Message msg = exchange.getIn();
diff --git a/components/camel-mybatis/src/test/java/org/apache/camel/component/mybatis/MyBatisConsumerIsolatedTest.java b/components/camel-mybatis/src/test/java/org/apache/camel/component/mybatis/MyBatisConsumerIsolatedTest.java
deleted file mode 100644
index 27ad1db..0000000
--- a/components/camel-mybatis/src/test/java/org/apache/camel/component/mybatis/MyBatisConsumerIsolatedTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.mybatis;
-
-import java.util.ArrayDeque;
-import java.util.Queue;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.Processor;
-import org.apache.camel.support.DefaultExchange;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Mockito.mock;
-
-public class MyBatisConsumerIsolatedTest {
-
-    @Test
-    public void shouldRespectBatchSize() throws Exception {
-        // Given
-        int batchSize = 5;
-        MyBatisConsumer consumer = new MyBatisConsumer(mock(MyBatisEndpoint.class), mock(Processor.class));
-        consumer.setMaxMessagesPerPoll(batchSize);
-
-        Queue<Object> emptyMessageQueue = new ArrayDeque<>();
-        for (int i = 0; i < 10; i++) {
-            MyBatisConsumer.DataHolder dataHolder = new MyBatisConsumer.DataHolder();
-            dataHolder.exchange = new DefaultExchange(mock(CamelContext.class));
-            emptyMessageQueue.add(dataHolder);
-        }
-
-        // When
-        int processedMessages = consumer.processBatch(emptyMessageQueue);
-
-        // Then
-        assertEquals(batchSize, processedMessages);
-    }
-
-}
diff --git a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java
index 11b15d7..84cc5c1 100644
--- a/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java
+++ b/components/camel-nats/src/main/java/org/apache/camel/component/nats/NatsConsumer.java
@@ -153,30 +153,32 @@ public class NatsConsumer extends DefaultConsumer {
             @Override
             public void onMessage(Message msg) throws InterruptedException {
                 LOG.debug("Received Message: {}", msg);
-                Exchange exchange = getEndpoint().createExchange();
-                exchange.getIn().setBody(msg.getData());
-                exchange.getIn().setHeader(NatsConstants.NATS_REPLY_TO, msg.getReplyTo());
-                exchange.getIn().setHeader(NatsConstants.NATS_SID, msg.getSID());
-                exchange.getIn().setHeader(NatsConstants.NATS_SUBJECT, msg.getSubject());
-                exchange.getIn().setHeader(NatsConstants.NATS_QUEUE_NAME, msg.getSubscription().getQueueName());
-                exchange.getIn().setHeader(NatsConstants.NATS_MESSAGE_TIMESTAMP, System.currentTimeMillis());
+                Exchange exchange = createExchange(false);
                 try {
+                    exchange.getIn().setBody(msg.getData());
+                    exchange.getIn().setHeader(NatsConstants.NATS_REPLY_TO, msg.getReplyTo());
+                    exchange.getIn().setHeader(NatsConstants.NATS_SID, msg.getSID());
+                    exchange.getIn().setHeader(NatsConstants.NATS_SUBJECT, msg.getSubject());
+                    exchange.getIn().setHeader(NatsConstants.NATS_QUEUE_NAME, msg.getSubscription().getQueueName());
+                    exchange.getIn().setHeader(NatsConstants.NATS_MESSAGE_TIMESTAMP, System.currentTimeMillis());
+
                     processor.process(exchange);
-                } catch (Exception e) {
-                    getExceptionHandler().handleException("Error during processing", exchange, e);
-                }
 
-                // is there a reply?
-                if (!configuration.isReplyToDisabled()
-                        && msg.getReplyTo() != null && msg.getConnection() != null) {
-                    Connection con = msg.getConnection();
-                    byte[] data = exchange.getMessage().getBody(byte[].class);
-                    if (data != null) {
-                        LOG.debug("Publishing replyTo: {} message", msg.getReplyTo());
-                        con.publish(msg.getReplyTo(), data);
+                    // is there a reply?
+                    if (!configuration.isReplyToDisabled()
+                            && msg.getReplyTo() != null && msg.getConnection() != null) {
+                        Connection con = msg.getConnection();
+                        byte[] data = exchange.getMessage().getBody(byte[].class);
+                        if (data != null) {
+                            LOG.debug("Publishing replyTo: {} message", msg.getReplyTo());
+                            con.publish(msg.getReplyTo(), data);
+                        }
                     }
+                } catch (Exception e) {
+                    getExceptionHandler().handleException("Error during processing", exchange, e);
+                } finally {
+                    releaseExchange(exchange, false);
                 }
-
             }
         }
     }
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java
index 476aa86..1d5e8e2 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpEndpoint.java
@@ -18,13 +18,9 @@ package org.apache.camel.component.netty.http;
 
 import java.util.Map;
 
-import io.netty.channel.ChannelHandlerContext;
-import io.netty.handler.codec.http.FullHttpRequest;
 import org.apache.camel.AsyncEndpoint;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
 import org.apache.camel.PollingConsumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
@@ -121,34 +117,6 @@ public class NettyHttpEndpoint extends NettyEndpoint implements AsyncEndpoint, H
     }
 
     @Override
-    public Exchange createExchange(ChannelHandlerContext ctx, Object message) throws Exception {
-        Exchange exchange = createExchange();
-
-        Message in;
-        if (message instanceof FullHttpRequest) {
-            FullHttpRequest request = (FullHttpRequest) message;
-            in = getNettyHttpBinding().toCamelMessage(request, exchange, getConfiguration());
-        } else {
-            InboundStreamHttpRequest request = (InboundStreamHttpRequest) message;
-            in = getNettyHttpBinding().toCamelMessage(request, exchange, getConfiguration());
-        }
-        exchange.setIn(in);
-
-        // setup the common message headers
-        updateMessageHeader(in, ctx);
-
-        // honor the character encoding
-        String contentType = in.getHeader(Exchange.CONTENT_TYPE, String.class);
-        String charset = NettyHttpHelper.getCharsetFromContentType(contentType);
-        if (charset != null) {
-            exchange.setProperty(Exchange.CHARSET_NAME, charset);
-            in.setHeader(Exchange.HTTP_CHARACTER_ENCODING, charset);
-        }
-
-        return exchange;
-    }
-
-    @Override
     public boolean isLenientProperties() {
         // true to allow dynamic URI options to be configured and passed to external system for eg. the HttpProducer
         return true;
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpMessage.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpMessage.java
index e1a50c5..bbe3331 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpMessage.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpMessage.java
@@ -29,8 +29,8 @@ import org.apache.camel.support.DefaultMessage;
  */
 public class NettyHttpMessage extends DefaultMessage {
 
-    private final transient FullHttpRequest httpRequest;
-    private final transient FullHttpResponse httpResponse;
+    private FullHttpRequest httpRequest;
+    private FullHttpResponse httpResponse;
 
     public NettyHttpMessage(CamelContext camelContext, FullHttpRequest httpRequest, FullHttpResponse httpResponse) {
         super(camelContext);
@@ -38,14 +38,29 @@ public class NettyHttpMessage extends DefaultMessage {
         this.httpResponse = httpResponse;
     }
 
+    @Override
+    public void reset() {
+        super.reset();
+        httpRequest = null;
+        httpResponse = null;
+    }
+
     public FullHttpRequest getHttpRequest() {
         return httpRequest;
     }
 
+    public void setHttpRequest(FullHttpRequest httpRequest) {
+        this.httpRequest = httpRequest;
+    }
+
     public FullHttpResponse getHttpResponse() {
         return httpResponse;
     }
 
+    public void setHttpResponse(FullHttpResponse httpResponse) {
+        this.httpResponse = httpResponse;
+    }
+
     @Override
     public DefaultMessage newInstance() {
         return new NettyHttpMessage(getCamelContext(), httpRequest, httpResponse);
diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
index 69ac775..ded58a9 100644
--- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
+++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/handlers/HttpServerChannelHandler.java
@@ -29,6 +29,7 @@ import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.DecoderResult;
 import io.netty.handler.codec.base64.Base64;
 import io.netty.handler.codec.http.DefaultHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
 import io.netty.handler.codec.http.HttpHeaderNames;
 import io.netty.handler.codec.http.HttpHeaderValues;
 import io.netty.handler.codec.http.HttpRequest;
@@ -44,6 +45,7 @@ import org.apache.camel.component.netty.http.HttpPrincipal;
 import org.apache.camel.component.netty.http.InboundStreamHttpRequest;
 import org.apache.camel.component.netty.http.NettyHttpConfiguration;
 import org.apache.camel.component.netty.http.NettyHttpConsumer;
+import org.apache.camel.component.netty.http.NettyHttpHelper;
 import org.apache.camel.component.netty.http.NettyHttpSecurityConfiguration;
 import org.apache.camel.component.netty.http.SecurityAuthenticator;
 import org.apache.camel.spi.CamelLogger;
@@ -339,4 +341,32 @@ public class HttpServerChannelHandler extends ServerChannelHandler {
         return consumer.getEndpoint().getNettyHttpBinding().toNettyResponse(exchange.getMessage(), consumer.getConfiguration());
     }
 
+    @Override
+    protected Exchange createExchange(ChannelHandlerContext ctx, Object message) throws Exception {
+        Exchange exchange = consumer.createExchange(false);
+
+        // create a new IN message as we cannot reuse with netty
+        Message in;
+        if (message instanceof FullHttpRequest) {
+            FullHttpRequest request = (FullHttpRequest) message;
+            in = consumer.getEndpoint().getNettyHttpBinding().toCamelMessage(request, exchange, consumer.getConfiguration());
+        } else {
+            InboundStreamHttpRequest request = (InboundStreamHttpRequest) message;
+            in = consumer.getEndpoint().getNettyHttpBinding().toCamelMessage(request, exchange, consumer.getConfiguration());
+        }
+        exchange.setIn(in);
+
+        // setup the common message headers
+        consumer.getEndpoint().updateMessageHeader(in, ctx);
+
+        // honor the character encoding
+        String contentType = in.getHeader(Exchange.CONTENT_TYPE, String.class);
+        String charset = NettyHttpHelper.getCharsetFromContentType(contentType);
+        if (charset != null) {
+            exchange.setProperty(Exchange.CHARSET_NAME, charset);
+            in.setHeader(Exchange.HTTP_CHARACTER_ENCODING, charset);
+        }
+
+        return exchange;
+    }
 }
diff --git a/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimplePooledExchangeTest.java b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimplePooledExchangeTest.java
new file mode 100644
index 0000000..d2e9634
--- /dev/null
+++ b/components/camel-netty-http/src/test/java/org/apache/camel/component/netty/http/NettyHttpSimplePooledExchangeTest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.netty.http;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.engine.PooledExchangeFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class NettyHttpSimplePooledExchangeTest extends BaseNettyTest {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext camelContext = super.createCamelContext();
+        camelContext.adapt(ExtendedCamelContext.class).setExchangeFactory(new PooledExchangeFactory());
+        return camelContext;
+    }
+
+    @Test
+    public void testOne() throws Exception {
+        getMockEndpoint("mock:input").expectedBodiesReceived("World");
+
+        String out = template.requestBody("netty-http:http://localhost:{{port}}/foo", "World", String.class);
+        assertEquals("Bye World", out);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testTwo() throws Exception {
+        getMockEndpoint("mock:input").expectedBodiesReceived("World", "Camel");
+
+        String out = template.requestBody("netty-http:http://localhost:{{port}}/foo", "World", String.class);
+        assertEquals("Bye World", out);
+
+        out = template.requestBody("netty-http:http://localhost:{{port}}/foo", "Camel", String.class);
+        assertEquals("Bye Camel", out);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("netty-http:http://0.0.0.0:{{port}}/foo")
+                        .convertBodyTo(String.class)
+                        .to("mock:input")
+                        .transform().simple("Bye ${body}");
+            }
+        };
+    }
+
+}
diff --git a/components/camel-netty/src/main/java/org/apache/camel/component/netty/DefaultServerInitializerFactory.java b/components/camel-netty/src/main/java/org/apache/camel/component/netty/DefaultServerInitializerFactory.java
index 2075bad..dfb605d 100644
--- a/components/camel-netty/src/main/java/org/apache/camel/component/netty/DefaultServerInitializerFactory.java
+++ b/components/camel-netty/src/main/java/org/apache/camel/component/netty/DefaultServerInitializerFactory.java
@@ -189,5 +189,4 @@ public class DefaultServerInitializerFactory extends ServerInitializerFactory {
     public ServerInitializerFactory createPipelineFactory(NettyConsumer consumer) {
         return new DefaultServerInitializerFactory(consumer);
     }
-
 }
diff --git a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyEndpoint.java b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyEndpoint.java
index 6ced9ba..bf9449d 100644
--- a/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyEndpoint.java
+++ b/components/camel-netty/src/main/java/org/apache/camel/component/netty/NettyEndpoint.java
@@ -28,7 +28,6 @@ import io.netty.handler.ssl.SslHandler;
 import org.apache.camel.AsyncEndpoint;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
@@ -83,13 +82,6 @@ public class NettyEndpoint extends DefaultEndpoint implements AsyncEndpoint {
         }
     }
 
-    public Exchange createExchange(ChannelHandlerContext ctx, Object message) throws Exception {
-        Exchange exchange = createExchange();
-        updateMessageHeader(exchange.getIn(), ctx);
-        NettyPayloadHelper.setIn(exchange, message);
-        return exchange;
-    }
-
     @Override
     public NettyComponent getComponent() {
         return (NettyComponent) super.getComponent();
@@ -119,7 +111,7 @@ public class NettyEndpoint extends DefaultEndpoint implements AsyncEndpoint {
         return sslSession;
     }
 
-    protected void updateMessageHeader(Message in, ChannelHandlerContext ctx) {
+    public void updateMessageHeader(Message in, ChannelHandlerContext ctx) {
         in.setHeader(NettyConstants.NETTY_CHANNEL_HANDLER_CONTEXT, ctx);
         in.setHeader(NettyConstants.NETTY_REMOTE_ADDRESS, ctx.channel().remoteAddress());
         in.setHeader(NettyConstants.NETTY_LOCAL_ADDRESS, ctx.channel().localAddress());
diff --git a/components/camel-netty/src/main/java/org/apache/camel/component/netty/handlers/ServerChannelHandler.java b/components/camel-netty/src/main/java/org/apache/camel/component/netty/handlers/ServerChannelHandler.java
index dd5b0a4..b40e0c6 100644
--- a/components/camel-netty/src/main/java/org/apache/camel/component/netty/handlers/ServerChannelHandler.java
+++ b/components/camel-netty/src/main/java/org/apache/camel/component/netty/handlers/ServerChannelHandler.java
@@ -88,7 +88,7 @@ public class ServerChannelHandler extends SimpleChannelInboundHandler<Object> {
         }
 
         // create Exchange and let the consumer process it
-        final Exchange exchange = consumer.getEndpoint().createExchange(ctx, msg);
+        final Exchange exchange = createExchange(ctx, msg);
         if (consumer.getConfiguration().isSync()) {
             exchange.setPattern(ExchangePattern.InOut);
         }
@@ -114,6 +114,13 @@ public class ServerChannelHandler extends SimpleChannelInboundHandler<Object> {
         }
     }
 
+    protected Exchange createExchange(ChannelHandlerContext ctx, Object message) throws Exception {
+        Exchange exchange = consumer.createExchange(false);
+        consumer.getEndpoint().updateMessageHeader(exchange.getIn(), ctx);
+        NettyPayloadHelper.setIn(exchange, message);
+        return exchange;
+    }
+
     /**
      * Allows any custom logic before the {@link Exchange} is processed by the routing engine.
      *
@@ -135,6 +142,7 @@ public class ServerChannelHandler extends SimpleChannelInboundHandler<Object> {
             consumer.getExceptionHandler().handleException(e);
         } finally {
             consumer.doneUoW(exchange);
+            consumer.releaseExchange(exchange, false);
         }
     }
 
@@ -151,6 +159,7 @@ public class ServerChannelHandler extends SimpleChannelInboundHandler<Object> {
                     consumer.getExceptionHandler().handleException(e);
                 } finally {
                     consumer.doneUoW(exchange);
+                    consumer.releaseExchange(exchange, false);
                 }
             }
         });
diff --git a/components/camel-netty/src/test/java/org/apache/camel/component/netty/NettyTextlineInOnlyPooledExchangeTest.java b/components/camel-netty/src/test/java/org/apache/camel/component/netty/NettyTextlineInOnlyPooledExchangeTest.java
new file mode 100644
index 0000000..f66ad38
--- /dev/null
+++ b/components/camel-netty/src/test/java/org/apache/camel/component/netty/NettyTextlineInOnlyPooledExchangeTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.netty;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.engine.PooledExchangeFactory;
+import org.junit.jupiter.api.Test;
+
+public class NettyTextlineInOnlyPooledExchangeTest extends BaseNettyTest {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext camelContext = super.createCamelContext();
+        camelContext.adapt(ExtendedCamelContext.class).setExchangeFactory(new PooledExchangeFactory());
+        return camelContext;
+    }
+
+    @Test
+    public void testOne() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hello World");
+
+        template.sendBody("netty:tcp://localhost:{{port}}?textline=true&sync=false", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testTwo() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hello World", "Bye World");
+
+        template.sendBody("netty:tcp://localhost:{{port}}?textline=true&sync=false", "Hello World");
+        template.sendBody("netty:tcp://localhost:{{port}}?textline=true&sync=false", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("netty:tcp://localhost:{{port}}?textline=true&sync=false")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-nitrite/src/main/java/org/apache/camel/component/nitrite/NitriteConsumer.java b/components/camel-nitrite/src/main/java/org/apache/camel/component/nitrite/NitriteConsumer.java
index a9fd003..8742460 100644
--- a/components/camel-nitrite/src/main/java/org/apache/camel/component/nitrite/NitriteConsumer.java
+++ b/components/camel-nitrite/src/main/java/org/apache/camel/component/nitrite/NitriteConsumer.java
@@ -61,7 +61,7 @@ public class NitriteConsumer extends DefaultConsumer {
         @Override
         public void onChange(ChangeInfo changeInfo) {
             for (ChangedItem changedItem : changeInfo.getChangedItems()) {
-                Exchange exchange = endpoint.createExchange();
+                Exchange exchange = createExchange(false);
                 Message message = exchange.getMessage();
                 message.setHeader(NitriteConstants.CHANGE_TIMESTAMP, changedItem.getChangeTimestamp());
                 message.setHeader(NitriteConstants.CHANGE_TYPE, changedItem.getChangeType());
@@ -75,6 +75,7 @@ public class NitriteConsumer extends DefaultConsumer {
                     if (exchange.getException() != null) {
                         getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
                     }
+                    releaseExchange(exchange, false);
                 }
             }
         }
diff --git a/components/camel-nsq/src/main/java/org/apache/camel/component/nsq/NsqConsumer.java b/components/camel-nsq/src/main/java/org/apache/camel/component/nsq/NsqConsumer.java
index 10c44fb..04b9514 100644
--- a/components/camel-nsq/src/main/java/org/apache/camel/component/nsq/NsqConsumer.java
+++ b/components/camel-nsq/src/main/java/org/apache/camel/component/nsq/NsqConsumer.java
@@ -111,12 +111,13 @@ public class NsqConsumer extends DefaultConsumer {
         @Override
         public void message(NSQMessage msg) {
             LOG.debug("Received Message: {}", msg);
-            Exchange exchange = getEndpoint().createExchange(ExchangePattern.InOnly);
-            exchange.getIn().setBody(msg.getMessage());
-            exchange.getIn().setHeader(NsqConstants.NSQ_MESSAGE_ID, msg.getId());
-            exchange.getIn().setHeader(NsqConstants.NSQ_MESSAGE_ATTEMPTS, msg.getAttempts());
-            exchange.getIn().setHeader(NsqConstants.NSQ_MESSAGE_TIMESTAMP, msg.getTimestamp());
+            Exchange exchange = createExchange(false);
             try {
+                exchange.setPattern(ExchangePattern.InOnly);
+                exchange.getIn().setBody(msg.getMessage());
+                exchange.getIn().setHeader(NsqConstants.NSQ_MESSAGE_ID, msg.getId());
+                exchange.getIn().setHeader(NsqConstants.NSQ_MESSAGE_ATTEMPTS, msg.getAttempts());
+                exchange.getIn().setHeader(NsqConstants.NSQ_MESSAGE_TIMESTAMP, msg.getTimestamp());
                 if (configuration.getAutoFinish()) {
                     msg.finished();
                 } else {
@@ -129,6 +130,8 @@ public class NsqConsumer extends DefaultConsumer {
                     msg.requeue((int) configuration.getRequeueInterval());
                 }
                 getExceptionHandler().handleException("Error during processing", exchange, e);
+            } finally {
+                releaseExchange(exchange, false);
             }
         }
     }
diff --git a/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/handler/AbstractHandler.java b/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/handler/AbstractHandler.java
index 88cfd7d..a68a551 100644
--- a/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/handler/AbstractHandler.java
+++ b/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/handler/AbstractHandler.java
@@ -16,10 +16,10 @@
  */
 package org.apache.camel.oaipmh.handler;
 
+import org.apache.camel.Consumer;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
-import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.oaipmh.component.OAIPMHConsumer;
 import org.apache.camel.oaipmh.model.OAIPMHResponse;
 import org.apache.camel.spi.ExceptionHandler;
@@ -30,18 +30,20 @@ public abstract class AbstractHandler {
 
     private static final Logger LOG = LoggerFactory.getLogger(AbstractHandler.class);
 
+    protected final Consumer consumer;
     protected final Endpoint endpoint;
     protected final Processor processor;
     protected final ExceptionHandler exceptionHandler;
 
     public AbstractHandler(OAIPMHConsumer consumer) {
+        this.consumer = consumer;
         this.endpoint = consumer.getEndpoint();
         this.processor = consumer.getAsyncProcessor();
         this.exceptionHandler = consumer.getExceptionHandler();
     }
 
     protected void send(OAIPMHResponse message) {
-        Exchange exchange = endpoint.createExchange();
+        Exchange exchange = consumer.createExchange(false);
         String xml = message.getRawResponse();
         exchange.getIn().setBody(xml);
         try {
@@ -49,12 +51,13 @@ public abstract class AbstractHandler {
             LOG.trace("sending exchange: {}", exchange);
             processor.process(exchange);
         } catch (Exception e) {
-            throw new RuntimeCamelException("Error sending exchange: " + exchange, e);
+            exchange.setException(e);
         } finally {
             // log exception if an exception occurred and was not handled
             if (exchange.getException() != null) {
                 exceptionHandler.handleException("Error processing exchange", exchange, exchange.getException());
             }
+            consumer.releaseExchange(exchange, false);
         }
     }
 
diff --git a/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/handler/Harvester.java b/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/handler/Harvester.java
index 494b426..b05ebc1 100644
--- a/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/handler/Harvester.java
+++ b/components/camel-oaipmh/src/main/java/org/apache/camel/oaipmh/handler/Harvester.java
@@ -16,16 +16,10 @@
  */
 package org.apache.camel.oaipmh.handler;
 
-import java.io.IOException;
 import java.net.URI;
-import java.net.URISyntaxException;
 import java.util.List;
 import java.util.Optional;
 
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.xml.sax.SAXException;
-
 import org.apache.camel.oaipmh.component.model.OAIPMHVerb;
 import org.apache.camel.oaipmh.model.OAIPMHResponse;
 import org.apache.camel.oaipmh.utils.OAIPMHHttpClient;
@@ -69,7 +63,7 @@ public class Harvester {
 
     }
 
-    private boolean harvest() throws IOException, URISyntaxException, ParserConfigurationException, SAXException, Exception {
+    private boolean harvest() throws Exception {
         boolean hasNext = false;
         if (!this.empty) {
             String responseXML = httpClient.doRequest(this.baseURI, this.verb, this.set, this.from, this.until, this.metadata,
@@ -88,13 +82,11 @@ public class Harvester {
         return hasNext;
     }
 
-    public void asynHarvest() throws IOException, URISyntaxException, ParserConfigurationException, SAXException, Exception {
+    public void asynHarvest() throws Exception {
         this.harvest();
-
     }
 
-    public List<String> synHarvest(boolean onlyFirst)
-            throws IOException, URISyntaxException, ParserConfigurationException, SAXException, Exception {
+    public List<String> synHarvest(boolean onlyFirst) throws Exception {
         while (this.harvest()) {
             if (onlyFirst) {
                 break;
diff --git a/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConsumer.java b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConsumer.java
index 3ea6ccf..a4dc33f 100644
--- a/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConsumer.java
+++ b/components/camel-optaplanner/src/main/java/org/apache/camel/component/optaplanner/OptaPlannerConsumer.java
@@ -59,22 +59,22 @@ public class OptaPlannerConsumer extends DefaultConsumer {
     }
 
     public void processEvent(BestSolutionChangedEvent<Object> event) {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getMessage().setHeader(OptaPlannerConstants.BEST_SOLUTION, event.getNewBestSolution());
         try {
             getProcessor().process(exchange);
         } catch (Exception e) {
-            LOG.error("Error processing event ", e);
+            getExceptionHandler().handleException(e);
         }
     }
 
     public void processSolverJobEvent(OptaplannerSolutionEvent event) {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         exchange.getMessage().setHeader(OptaPlannerConstants.BEST_SOLUTION, event.getBestSolution());
         try {
             getProcessor().process(exchange);
         } catch (Exception e) {
-            LOG.error("Error processing event ", e);
+            getExceptionHandler().handleException(e);
         }
     }
 
diff --git a/components/camel-paho-mqtt5/src/main/java/org/apache/camel/component/paho/mqtt5/PahoMqtt5Consumer.java b/components/camel-paho-mqtt5/src/main/java/org/apache/camel/component/paho/mqtt5/PahoMqtt5Consumer.java
index 57260b0..af8345a 100644
--- a/components/camel-paho-mqtt5/src/main/java/org/apache/camel/component/paho/mqtt5/PahoMqtt5Consumer.java
+++ b/components/camel-paho-mqtt5/src/main/java/org/apache/camel/component/paho/mqtt5/PahoMqtt5Consumer.java
@@ -103,7 +103,7 @@ public class PahoMqtt5Consumer extends DefaultConsumer {
             @Override
             public void messageArrived(String topic, MqttMessage message) throws Exception {
                 LOG.debug("Message arrived on topic: {} -> {}", topic, message);
-                Exchange exchange = getEndpoint().createExchange(message, topic);
+                Exchange exchange = createExchange(message, topic);
 
                 getAsyncProcessor().process(exchange, doneSync -> {
                     // noop
@@ -144,4 +144,16 @@ public class PahoMqtt5Consumer extends DefaultConsumer {
         return (PahoMqtt5Endpoint) super.getEndpoint();
     }
 
+    public Exchange createExchange(MqttMessage mqttMessage, String topic) {
+        Exchange exchange = createExchange(true);
+
+        PahoMqtt5Message paho = new PahoMqtt5Message(exchange.getContext(), mqttMessage);
+        paho.setBody(mqttMessage.getPayload());
+        paho.setHeader(PahoMqtt5Constants.MQTT_TOPIC, topic);
+        paho.setHeader(PahoMqtt5Constants.MQTT_QOS, mqttMessage.getQos());
+
+        exchange.setIn(paho);
+        return exchange;
+    }
+
 }
diff --git a/components/camel-paho-mqtt5/src/main/java/org/apache/camel/component/paho/mqtt5/PahoMqtt5Endpoint.java b/components/camel-paho-mqtt5/src/main/java/org/apache/camel/component/paho/mqtt5/PahoMqtt5Endpoint.java
index f558ac1..725df0d 100644
--- a/components/camel-paho-mqtt5/src/main/java/org/apache/camel/component/paho/mqtt5/PahoMqtt5Endpoint.java
+++ b/components/camel-paho-mqtt5/src/main/java/org/apache/camel/component/paho/mqtt5/PahoMqtt5Endpoint.java
@@ -20,7 +20,6 @@ import java.util.UUID;
 
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.spi.Metadata;
@@ -83,18 +82,6 @@ public class PahoMqtt5Endpoint extends DefaultEndpoint {
         return topic;
     }
 
-    public Exchange createExchange(MqttMessage mqttMessage, String topic) {
-        Exchange exchange = createExchange();
-
-        PahoMqtt5Message paho = new PahoMqtt5Message(exchange.getContext(), mqttMessage);
-        paho.setBody(mqttMessage.getPayload());
-        paho.setHeader(PahoMqtt5Constants.MQTT_TOPIC, topic);
-        paho.setHeader(PahoMqtt5Constants.MQTT_QOS, mqttMessage.getQos());
-
-        exchange.setIn(paho);
-        return exchange;
-    }
-
     protected MqttConnectionOptions createMqttConnectionOptions() {
         PahoMqtt5Configuration config = getConfiguration();
         MqttConnectionOptions options = new MqttConnectionOptions();
diff --git a/components/camel-paho/src/main/java/org/apache/camel/component/paho/PahoConsumer.java b/components/camel-paho/src/main/java/org/apache/camel/component/paho/PahoConsumer.java
index 4e42547..f908efd 100644
--- a/components/camel-paho/src/main/java/org/apache/camel/component/paho/PahoConsumer.java
+++ b/components/camel-paho/src/main/java/org/apache/camel/component/paho/PahoConsumer.java
@@ -92,7 +92,7 @@ public class PahoConsumer extends DefaultConsumer {
             @Override
             public void messageArrived(String topic, MqttMessage message) throws Exception {
                 LOG.debug("Message arrived on topic: {} -> {}", topic, message);
-                Exchange exchange = getEndpoint().createExchange(message, topic);
+                Exchange exchange = createExchange(message, topic);
 
                 getAsyncProcessor().process(exchange, new AsyncCallback() {
                     @Override
@@ -136,4 +136,16 @@ public class PahoConsumer extends DefaultConsumer {
         return (PahoEndpoint) super.getEndpoint();
     }
 
+    public Exchange createExchange(MqttMessage mqttMessage, String topic) {
+        Exchange exchange = createExchange(true);
+
+        PahoMessage paho = new PahoMessage(exchange.getContext(), mqttMessage);
+        paho.setBody(mqttMessage.getPayload());
+        paho.setHeader(PahoConstants.MQTT_TOPIC, topic);
+        paho.setHeader(PahoConstants.MQTT_QOS, mqttMessage.getQos());
+
+        exchange.setIn(paho);
+        return exchange;
+    }
+
 }
diff --git a/components/camel-paho/src/main/java/org/apache/camel/component/paho/PahoEndpoint.java b/components/camel-paho/src/main/java/org/apache/camel/component/paho/PahoEndpoint.java
index 920cc28..d885204 100644
--- a/components/camel-paho/src/main/java/org/apache/camel/component/paho/PahoEndpoint.java
+++ b/components/camel-paho/src/main/java/org/apache/camel/component/paho/PahoEndpoint.java
@@ -18,7 +18,6 @@ package org.apache.camel.component.paho;
 
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.spi.Metadata;
@@ -30,7 +29,6 @@ import org.apache.camel.util.ObjectHelper;
 import org.eclipse.paho.client.mqttv3.MqttClient;
 import org.eclipse.paho.client.mqttv3.MqttClientPersistence;
 import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
-import org.eclipse.paho.client.mqttv3.MqttMessage;
 import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
 import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
 
@@ -80,18 +78,6 @@ public class PahoEndpoint extends DefaultEndpoint {
         return topic;
     }
 
-    public Exchange createExchange(MqttMessage mqttMessage, String topic) {
-        Exchange exchange = createExchange();
-
-        PahoMessage paho = new PahoMessage(exchange.getContext(), mqttMessage);
-        paho.setBody(mqttMessage.getPayload());
-        paho.setHeader(PahoConstants.MQTT_TOPIC, topic);
-        paho.setHeader(PahoConstants.MQTT_QOS, mqttMessage.getQos());
-
-        exchange.setIn(paho);
-        return exchange;
-    }
-
     protected static MqttConnectOptions createMqttConnectOptions(PahoConfiguration config) {
         MqttConnectOptions mq = new MqttConnectOptions();
         if (ObjectHelper.isNotEmpty(config.getUserName()) && ObjectHelper.isNotEmpty(config.getPassword())) {
diff --git a/components/camel-pg-replication-slot/src/main/java/org/apache/camel/component/pg/replication/slot/PgReplicationSlotConsumer.java b/components/camel-pg-replication-slot/src/main/java/org/apache/camel/component/pg/replication/slot/PgReplicationSlotConsumer.java
index 9b2dcc3..d911431 100644
--- a/components/camel-pg-replication-slot/src/main/java/org/apache/camel/component/pg/replication/slot/PgReplicationSlotConsumer.java
+++ b/components/camel-pg-replication-slot/src/main/java/org/apache/camel/component/pg/replication/slot/PgReplicationSlotConsumer.java
@@ -125,7 +125,7 @@ public class PgReplicationSlotConsumer extends ScheduledPollConsumer {
             throw e;
         }
 
-        Exchange exchange = this.endpoint.createExchange();
+        Exchange exchange = createExchange(true);
         exchange.setExchangeId(stream.getLastReceiveLSN().asString());
 
         Message message = exchange.getIn();
diff --git a/components/camel-pgevent/src/main/java/org/apache/camel/component/pgevent/PgEventConsumer.java b/components/camel-pgevent/src/main/java/org/apache/camel/component/pgevent/PgEventConsumer.java
index 0c248a4..aebe8e3 100644
--- a/components/camel-pgevent/src/main/java/org/apache/camel/component/pgevent/PgEventConsumer.java
+++ b/components/camel-pgevent/src/main/java/org/apache/camel/component/pgevent/PgEventConsumer.java
@@ -59,18 +59,22 @@ public class PgEventConsumer extends DefaultConsumer implements PGNotificationLi
             LOG.debug("Notification processId: {}, channel: {}, payload: {}", processId, channel, payload);
         }
 
-        Exchange exchange = endpoint.createExchange();
+        Exchange exchange = createExchange(false);
         Message msg = exchange.getIn();
         msg.setHeader("channel", channel);
         msg.setBody(payload);
 
         try {
             getProcessor().process(exchange);
-        } catch (Exception ex) {
+        } catch (Exception e) {
+            exchange.setException(e);
+        }
+        if (exchange.getException() != null) {
             String cause = "Unable to process incoming notification from PostgreSQL: processId='" + processId + "', channel='"
                            + channel + "', payload='" + payload + "'";
-            getExceptionHandler().handleException(cause, ex);
+            getExceptionHandler().handleException(cause, exchange.getException());
         }
+        releaseExchange(exchange, false);
     }
 
     @Override
diff --git a/components/camel-pgevent/src/test/java/org/apache/camel/pgevent/PgEventConsumerTest.java b/components/camel-pgevent/src/test/java/org/apache/camel/pgevent/PgEventConsumerTest.java
index 82ff432..196de5a 100644
--- a/components/camel-pgevent/src/test/java/org/apache/camel/pgevent/PgEventConsumerTest.java
+++ b/components/camel-pgevent/src/test/java/org/apache/camel/pgevent/PgEventConsumerTest.java
@@ -20,16 +20,19 @@ import java.sql.PreparedStatement;
 
 import com.impossibl.postgres.api.jdbc.PGConnection;
 import com.impossibl.postgres.jdbc.PGDataSource;
-import org.apache.camel.Exchange;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.ExtendedExchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.component.pgevent.PgEventConsumer;
 import org.apache.camel.component.pgevent.PgEventEndpoint;
+import org.apache.camel.spi.ExchangeFactory;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -44,7 +47,13 @@ public class PgEventConsumerTest {
         PreparedStatement statement = mock(PreparedStatement.class);
         PgEventEndpoint endpoint = mock(PgEventEndpoint.class);
         Processor processor = mock(Processor.class);
+        ExtendedCamelContext ecc = mock(ExtendedCamelContext.class);
+        ExchangeFactory ef = mock(ExchangeFactory.class);
 
+        when(endpoint.getCamelContext()).thenReturn(ecc);
+        when(ecc.adapt(ExtendedCamelContext.class)).thenReturn(ecc);
+        when(ecc.getExchangeFactory()).thenReturn(ef);
+        when(ef.newExchangeFactory(any())).thenReturn(ef);
         when(endpoint.getDatasource()).thenReturn(dataSource);
         when(dataSource.getConnection()).thenReturn(connection);
         when(connection.prepareStatement("LISTEN camel")).thenReturn(statement);
@@ -64,7 +73,13 @@ public class PgEventConsumerTest {
         PreparedStatement statement = mock(PreparedStatement.class);
         PgEventEndpoint endpoint = mock(PgEventEndpoint.class);
         Processor processor = mock(Processor.class);
+        ExtendedCamelContext ecc = mock(ExtendedCamelContext.class);
+        ExchangeFactory ef = mock(ExchangeFactory.class);
 
+        when(endpoint.getCamelContext()).thenReturn(ecc);
+        when(ecc.adapt(ExtendedCamelContext.class)).thenReturn(ecc);
+        when(ecc.getExchangeFactory()).thenReturn(ef);
+        when(ef.newExchangeFactory(any())).thenReturn(ef);
         when(endpoint.getDatasource()).thenReturn(dataSource);
         when(dataSource.getConnection()).thenReturn(connection);
         when(connection.prepareStatement("LISTEN camel")).thenReturn(statement);
@@ -84,10 +99,17 @@ public class PgEventConsumerTest {
     public void testPgEventNotification() throws Exception {
         PgEventEndpoint endpoint = mock(PgEventEndpoint.class);
         Processor processor = mock(Processor.class);
-        Exchange exchange = mock(Exchange.class);
+        ExtendedExchange exchange = mock(ExtendedExchange.class);
         Message message = mock(Message.class);
-
-        when(endpoint.createExchange()).thenReturn(exchange);
+        ExtendedCamelContext ecc = mock(ExtendedCamelContext.class);
+        ExchangeFactory ef = mock(ExchangeFactory.class);
+
+        when(endpoint.getCamelContext()).thenReturn(ecc);
+        when(ecc.adapt(ExtendedCamelContext.class)).thenReturn(ecc);
+        when(ecc.getExchangeFactory()).thenReturn(ef);
+        when(ef.newExchangeFactory(any())).thenReturn(ef);
+        when(ef.create(endpoint, false)).thenReturn(exchange);
+        when(exchange.adapt(ExtendedExchange.class)).thenReturn(exchange);
         when(exchange.getIn()).thenReturn(message);
 
         PgEventConsumer consumer = new PgEventConsumer(endpoint, processor);
diff --git a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
index 8937de5..e49748f 100644
--- a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
+++ b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
@@ -35,6 +35,7 @@ import io.vertx.ext.web.FileUpload;
 import io.vertx.ext.web.Route;
 import io.vertx.ext.web.RoutingContext;
 import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.attachment.AttachmentMessage;
@@ -43,7 +44,6 @@ import org.apache.camel.component.platform.http.PlatformHttpEndpoint;
 import org.apache.camel.component.platform.http.spi.Method;
 import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.support.DefaultConsumer;
-import org.apache.camel.support.DefaultMessage;
 import org.apache.camel.util.FileUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -64,11 +64,10 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer {
     private final String fileNameExtWhitelist;
     private Set<Method> methods;
     private String path;
-
     private Route route;
+    private VertxPlatformHttpRouter router;
 
-    public VertxPlatformHttpConsumer(
-                                     PlatformHttpEndpoint endpoint,
+    public VertxPlatformHttpConsumer(PlatformHttpEndpoint endpoint,
                                      Processor processor,
                                      List<Handler<RoutingContext>> handlers) {
         super(endpoint, processor);
@@ -88,13 +87,13 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer {
         super.doInit();
         methods = Method.parseList(getEndpoint().getHttpMethodRestrict());
         path = configureEndpointPath(getEndpoint());
+        router = VertxPlatformHttpRouter.lookup(getEndpoint().getCamelContext());
     }
 
     @Override
     protected void doStart() throws Exception {
         super.doStart();
 
-        final VertxPlatformHttpRouter router = VertxPlatformHttpRouter.lookup(getEndpoint().getCamelContext());
         final Route newRoute = router.route(path);
 
         if (!methods.equals(Method.getAll())) {
@@ -145,7 +144,7 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer {
 
     private String configureEndpointPath(PlatformHttpEndpoint endpoint) {
         String path = endpoint.getPath();
-        if (endpoint.isMatchOnUriPrefix()) {
+        if (endpoint.isMatchOnUriPrefix() && !path.endsWith("*")) {
             path += "*";
         }
         // Transform from the Camel path param syntax /path/{key} to vert.x web's /path/:key
@@ -211,26 +210,25 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer {
                         }
                     } finally {
                         doneUoW(exchange);
+                        releaseExchange(exchange, false);
                     }
                 });
     }
 
     private Exchange toExchange(RoutingContext ctx) {
-        final Exchange exchange = getEndpoint().createExchange();
+        final Exchange exchange = createExchange(false);
+        exchange.setPattern(ExchangePattern.InOut);
         final Message in = toCamelMessage(ctx, exchange);
-
         final String charset = ctx.parsedHeaders().contentType().parameter("charset");
         if (charset != null) {
             exchange.setProperty(Exchange.CHARSET_NAME, charset);
             in.setHeader(Exchange.HTTP_CHARACTER_ENCODING, charset);
         }
-
-        exchange.setIn(in);
         return exchange;
     }
 
     private Message toCamelMessage(RoutingContext ctx, Exchange exchange) {
-        final Message result = new DefaultMessage(exchange);
+        final Message result = exchange.getIn();
 
         final HeaderFilterStrategy headerFilterStrategy = getEndpoint().getHeaderFilterStrategy();
         populateCamelHeaders(ctx, result.getHeaders(), exchange, headerFilterStrategy);
diff --git a/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubConsumer.java b/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubConsumer.java
index 243aeb0..ad3e200 100644
--- a/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubConsumer.java
+++ b/components/camel-pubnub/src/main/java/org/apache/camel/component/pubnub/PubNubConsumer.java
@@ -103,7 +103,7 @@ public class PubNubConsumer extends DefaultConsumer {
 
         @Override
         public void message(PubNub pubnub, PNMessageResult message) {
-            Exchange exchange = endpoint.createExchange();
+            Exchange exchange = createExchange(true);
             Message inmessage = exchange.getIn();
             inmessage.setBody(message);
             inmessage.setHeader(TIMETOKEN, message.getTimetoken());
@@ -111,13 +111,13 @@ public class PubNubConsumer extends DefaultConsumer {
             try {
                 getProcessor().process(exchange);
             } catch (Exception e) {
-                getExceptionHandler().handleException("Error processing exchange", exchange, e);
+                getExceptionHandler().handleException("Error processing exchange", e);
             }
         }
 
         @Override
         public void presence(PubNub pubnub, PNPresenceEventResult presence) {
-            Exchange exchange = endpoint.createExchange();
+            Exchange exchange = createExchange(true);
             Message inmessage = exchange.getIn();
             inmessage.setBody(presence);
             inmessage.setHeader(TIMETOKEN, presence.getTimetoken());
@@ -125,8 +125,7 @@ public class PubNubConsumer extends DefaultConsumer {
             try {
                 getProcessor().process(exchange);
             } catch (Exception e) {
-                exchange.setException(e);
-                getExceptionHandler().handleException("Error processing exchange", exchange, e);
+                getExceptionHandler().handleException("Error processing exchange", e);
             }
         }
 
diff --git a/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarMessageListener.java b/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarMessageListener.java
index 0607bda..9038c35 100644
--- a/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarMessageListener.java
+++ b/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarMessageListener.java
@@ -16,7 +16,6 @@
  */
 package org.apache.camel.component.pulsar;
 
-import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
 import org.apache.camel.component.pulsar.utils.message.PulsarMessageHeaders;
 import org.apache.camel.component.pulsar.utils.message.PulsarMessageUtils;
@@ -24,13 +23,9 @@ import org.apache.pulsar.client.api.Consumer;
 import org.apache.pulsar.client.api.Message;
 import org.apache.pulsar.client.api.MessageListener;
 import org.apache.pulsar.client.api.PulsarClientException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class PulsarMessageListener implements MessageListener<byte[]> {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger(PulsarMessageListener.class);
-
     private final PulsarEndpoint endpoint;
     private final PulsarConsumer pulsarConsumer;
 
@@ -41,33 +36,32 @@ public class PulsarMessageListener implements MessageListener<byte[]> {
 
     @Override
     public void received(final Consumer<byte[]> consumer, final Message<byte[]> message) {
-        final Exchange exchange = PulsarMessageUtils.updateExchange(message, endpoint.createExchange());
+        final Exchange exchange = PulsarMessageUtils.updateExchange(message, pulsarConsumer.createExchange(false));
 
-        try {
-            if (endpoint.getPulsarConfiguration().isAllowManualAcknowledgement()) {
-                exchange.getIn().setHeader(PulsarMessageHeaders.MESSAGE_RECEIPT,
-                        endpoint.getComponent().getPulsarMessageReceiptFactory()
-                                .newInstance(exchange, message, consumer));
-            }
-            processAsync(exchange, consumer, message);
-        } catch (Exception exception) {
-            handleProcessorException(exchange, exception);
+        if (endpoint.getPulsarConfiguration().isAllowManualAcknowledgement()) {
+            exchange.getIn().setHeader(PulsarMessageHeaders.MESSAGE_RECEIPT,
+                    endpoint.getComponent().getPulsarMessageReceiptFactory()
+                            .newInstance(exchange, message, consumer));
         }
+        processAsync(exchange, consumer, message);
     }
 
     private void processAsync(final Exchange exchange, final Consumer<byte[]> consumer, final Message<byte[]> message) {
-        pulsarConsumer.getAsyncProcessor().process(exchange, new AsyncCallback() {
-            @Override
-            public void done(boolean doneSync) {
+        pulsarConsumer.getAsyncProcessor().process(exchange, doneSync -> {
+            try {
                 if (exchange.getException() != null) {
-                    handleProcessorException(exchange, exchange.getException());
+                    pulsarConsumer.getExceptionHandler().handleException("Error processing exchange", exchange,
+                            exchange.getException());
                 } else {
                     try {
                         acknowledge(consumer, message);
                     } catch (Exception e) {
-                        handleProcessorException(exchange, e);
+                        pulsarConsumer.getExceptionHandler().handleException("Error processing exchange", exchange,
+                                exchange.getException());
                     }
                 }
+            } finally {
+                pulsarConsumer.releaseExchange(exchange, false);
             }
         });
     }
@@ -79,12 +73,4 @@ public class PulsarMessageListener implements MessageListener<byte[]> {
         }
     }
 
-    private void handleProcessorException(final Exchange exchange, final Exception exception) {
-        final Exchange exchangeWithException = PulsarMessageUtils
-                .updateExchangeWithException(exception, exchange);
-
-        pulsarConsumer.getExceptionHandler()
-                .handleException("An error occurred", exchangeWithException, exception);
-    }
-
 }
diff --git a/components/camel-quickfix/src/main/java/org/apache/camel/component/quickfixj/QuickfixjEndpoint.java b/components/camel-quickfix/src/main/java/org/apache/camel/component/quickfixj/QuickfixjEndpoint.java
index 7725b0d..0f45d55 100644
--- a/components/camel-quickfix/src/main/java/org/apache/camel/component/quickfixj/QuickfixjEndpoint.java
+++ b/components/camel-quickfix/src/main/java/org/apache/camel/component/quickfixj/QuickfixjEndpoint.java
@@ -133,10 +133,15 @@ public class QuickfixjEndpoint extends DefaultEndpoint implements QuickfixjEvent
         if (this.sessionID == null || isMatching(sessionID)) {
             for (QuickfixjConsumer consumer : consumers) {
                 Exchange exchange
-                        = QuickfixjConverters.toExchange(this, sessionID, message, eventCategory, getExchangePattern());
-                consumer.onExchange(exchange);
-                if (exchange.getException() != null) {
-                    throw exchange.getException();
+                        = QuickfixjConverters.toExchange(consumer, sessionID, message, eventCategory, getExchangePattern());
+                try {
+                    consumer.onExchange(exchange);
+                    Exception cause = exchange.getException();
+                    if (cause != null) {
+                        throw cause;
+                    }
+                } finally {
+                    consumer.releaseExchange(exchange, false);
                 }
             }
         }
diff --git a/components/camel-quickfix/src/main/java/org/apache/camel/component/quickfixj/converter/QuickfixjConverters.java b/components/camel-quickfix/src/main/java/org/apache/camel/component/quickfixj/converter/QuickfixjConverters.java
index 426efb4..65304ee 100644
--- a/components/camel-quickfix/src/main/java/org/apache/camel/component/quickfixj/converter/QuickfixjConverters.java
+++ b/components/camel-quickfix/src/main/java/org/apache/camel/component/quickfixj/converter/QuickfixjConverters.java
@@ -20,6 +20,7 @@ import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 
+import org.apache.camel.Consumer;
 import org.apache.camel.Converter;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
@@ -143,4 +144,26 @@ public final class QuickfixjConverters {
         return exchange;
     }
 
+    public static Exchange toExchange(
+            Consumer consumer, SessionID sessionID, Message message, QuickfixjEventCategory eventCategory,
+            ExchangePattern exchangePattern) {
+        Exchange exchange = consumer.createExchange(false);
+        exchange.setPattern(exchangePattern);
+
+        org.apache.camel.Message camelMessage = exchange.getIn();
+        camelMessage.setHeader(EVENT_CATEGORY_KEY, eventCategory);
+        camelMessage.setHeader(SESSION_ID_KEY, sessionID);
+
+        if (message != null) {
+            try {
+                camelMessage.setHeader(MESSAGE_TYPE_KEY, message.getHeader().getString(MsgType.FIELD));
+            } catch (FieldNotFound e) {
+                LOG.warn("Message type field not found in QFJ message: {}, continuing...", message);
+            }
+        }
+        camelMessage.setBody(message);
+
+        return exchange;
+    }
+
 }
diff --git a/components/camel-quickfix/src/test/java/org/apache/camel/component/quickfixj/QuickfixjConsumerTest.java b/components/camel-quickfix/src/test/java/org/apache/camel/component/quickfixj/QuickfixjConsumerTest.java
deleted file mode 100644
index 4e9360a..0000000
--- a/components/camel-quickfix/src/test/java/org/apache/camel/component/quickfixj/QuickfixjConsumerTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.quickfixj;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.Processor;
-import org.hamcrest.CoreMatchers;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-import quickfix.FixVersions;
-import quickfix.Message;
-import quickfix.Session;
-import quickfix.SessionID;
-import quickfix.field.BeginString;
-import quickfix.field.SenderCompID;
-import quickfix.field.TargetCompID;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.ArgumentMatchers.isA;
-
-public class QuickfixjConsumerTest {
-    private Exchange mockExchange;
-    private Processor mockProcessor;
-    private QuickfixjEndpoint mockEndpoint;
-    private Message inboundFixMessage;
-
-    @BeforeEach
-    public void setUp() {
-
-        mockExchange = Mockito.mock(Exchange.class);
-        org.apache.camel.Message mockCamelMessage = Mockito.mock(org.apache.camel.Message.class);
-        Mockito.when(mockExchange.getIn()).thenReturn(mockCamelMessage);
-
-        inboundFixMessage = new Message();
-        inboundFixMessage.getHeader().setString(BeginString.FIELD, FixVersions.BEGINSTRING_FIX44);
-        inboundFixMessage.getHeader().setString(SenderCompID.FIELD, "SENDER");
-        inboundFixMessage.getHeader().setString(TargetCompID.FIELD, "TARGET");
-        Mockito.when(mockCamelMessage.getBody(quickfix.Message.class)).thenReturn(inboundFixMessage);
-
-        mockProcessor = Mockito.mock(Processor.class);
-        mockEndpoint = Mockito.mock(QuickfixjEndpoint.class);
-        Mockito.when(mockEndpoint.createExchange(ExchangePattern.InOnly)).thenReturn(mockExchange);
-    }
-
-    @Test
-    public void processExchangeOnlyWhenStarted() throws Exception {
-        QuickfixjConsumer consumer = new QuickfixjConsumer(mockEndpoint, mockProcessor);
-
-        assertThat("Consumer should not be automatically started",
-                consumer.isStarted(), CoreMatchers.is(false));
-
-        consumer.onExchange(mockExchange);
-
-        // No expected interaction with processor since component is not started
-        Mockito.verifyNoInteractions(mockProcessor);
-
-        consumer.start();
-        Mockito.verify(mockEndpoint).ensureInitialized();
-        assertThat(consumer.isStarted(), CoreMatchers.is(true));
-
-        consumer.onExchange(mockExchange);
-
-        // Second message should be processed
-        Mockito.verify(mockProcessor).process(isA(Exchange.class));
-    }
-
-    @Test
-    public void setExceptionOnExchange() throws Exception {
-        QuickfixjConsumer consumer = new QuickfixjConsumer(mockEndpoint, mockProcessor);
-        consumer.start();
-
-        Throwable exception = new Exception("Throwable for test");
-        Mockito.doThrow(exception).when(mockProcessor).process(mockExchange);
-
-        // Simulate a message from the FIX engine
-        consumer.onExchange(mockExchange);
-
-        Mockito.verify(mockExchange).setException(exception);
-    }
-
-    @Test
-    public void setExceptionOnInOutExchange() throws Exception {
-        org.apache.camel.Message mockCamelOutMessage = Mockito.mock(org.apache.camel.Message.class);
-        org.apache.camel.Message mockCamelInMessage = Mockito.mock(org.apache.camel.Message.class);
-        SessionID mockSessionId = Mockito.mock(SessionID.class);
-
-        QuickfixjConsumer consumer = Mockito.spy(new QuickfixjConsumer(mockEndpoint, mockProcessor));
-        Mockito.doReturn(null).when(consumer).getSession(mockSessionId);
-
-        Mockito.when(mockExchange.getPattern()).thenReturn(ExchangePattern.InOut);
-        Mockito.when(mockExchange.hasOut()).thenReturn(true);
-        Mockito.when(mockExchange.getMessage()).thenReturn(mockCamelOutMessage);
-        Message outboundFixMessage = new Message();
-        Mockito.when(mockCamelOutMessage.getBody(Message.class)).thenReturn(outboundFixMessage);
-        Mockito.when(mockExchange.getIn()).thenReturn(mockCamelInMessage);
-        Mockito.when(mockCamelInMessage.getHeader("SessionID", SessionID.class)).thenReturn(mockSessionId);
-
-        consumer.start();
-
-        // Simulate a message from the FIX engine
-        consumer.onExchange(mockExchange);
-
-        Mockito.verify(mockExchange).setException(isA(IllegalStateException.class));
-    }
-
-    @Test
-    public void processInOutExchange() throws Exception {
-        org.apache.camel.Message mockCamelOutMessage = Mockito.mock(org.apache.camel.Message.class);
-        org.apache.camel.Message mockCamelInMessage = Mockito.mock(org.apache.camel.Message.class);
-        SessionID mockSessionId = Mockito.mock(SessionID.class);
-        Session mockSession = Mockito.mock(Session.class);
-
-        QuickfixjConsumer consumer = Mockito.spy(new QuickfixjConsumer(mockEndpoint, mockProcessor));
-        Mockito.doReturn(mockSession).when(consumer).getSession(mockSessionId);
-        Mockito.doReturn(true).when(mockSession).send(isA(Message.class));
-
-        Mockito.when(mockExchange.getPattern()).thenReturn(ExchangePattern.InOut);
-        Mockito.when(mockExchange.hasOut()).thenReturn(true);
-        Mockito.when(mockExchange.getMessage()).thenReturn(mockCamelOutMessage);
-        Message outboundFixMessage = new Message();
-        Mockito.when(mockCamelOutMessage.getBody(Message.class)).thenReturn(outboundFixMessage);
-        Mockito.when(mockExchange.getIn()).thenReturn(mockCamelInMessage);
-        Mockito.when(mockCamelInMessage.getHeader("SessionID", SessionID.class)).thenReturn(mockSessionId);
-
-        consumer.start();
-
-        consumer.onExchange(mockExchange);
-        Mockito.verify(mockExchange, Mockito.never()).setException(isA(Exception.class));
-        Mockito.verify(mockSession).send(outboundFixMessage);
-    }
-}
diff --git a/components/camel-rabbitmq/src/main/java/org/apache/camel/component/rabbitmq/RabbitConsumer.java b/components/camel-rabbitmq/src/main/java/org/apache/camel/component/rabbitmq/RabbitConsumer.java
index f1bd416..4ffb480 100644
--- a/components/camel-rabbitmq/src/main/java/org/apache/camel/component/rabbitmq/RabbitConsumer.java
+++ b/components/camel-rabbitmq/src/main/java/org/apache/camel/component/rabbitmq/RabbitConsumer.java
@@ -69,7 +69,7 @@ class RabbitConsumer extends ServiceSupport implements com.rabbitmq.client.Consu
                 lock.acquire();
             }
             // Channel might be open because while we were waiting for the lock,
-            // stop() has been succesfully called.
+            // stop() has been successfully called.
             if (!channel.isOpen()) {
                 // we could not open the channel so release the lock
                 if (!consumer.getEndpoint().isAutoAck()) {
@@ -78,12 +78,15 @@ class RabbitConsumer extends ServiceSupport implements com.rabbitmq.client.Consu
                 return;
             }
 
+            Exchange exchange = consumer.createExchange(envelope, properties, body);
             try {
-                doHandleDelivery(consumerTag, envelope, properties, body);
+                consumer.getEndpoint().getMessageConverter().mergeAmqpProperties(exchange, properties);
+                doHandleDelivery(exchange, envelope, properties);
             } finally {
                 if (!consumer.getEndpoint().isAutoAck()) {
                     lock.release();
                 }
+                consumer.releaseExchange(exchange, false);
             }
 
         } catch (InterruptedException e) {
@@ -91,10 +94,8 @@ class RabbitConsumer extends ServiceSupport implements com.rabbitmq.client.Consu
         }
     }
 
-    public void doHandleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
+    public void doHandleDelivery(Exchange exchange, Envelope envelope, AMQP.BasicProperties properties)
             throws IOException {
-        Exchange exchange = consumer.getEndpoint().createRabbitExchange(envelope, properties, body);
-        consumer.getEndpoint().getMessageConverter().mergeAmqpProperties(exchange, properties);
 
         boolean sendReply = properties.getReplyTo() != null;
         if (sendReply && !exchange.getPattern().isOutCapable()) {
diff --git a/components/camel-rabbitmq/src/main/java/org/apache/camel/component/rabbitmq/RabbitMQConsumer.java b/components/camel-rabbitmq/src/main/java/org/apache/camel/component/rabbitmq/RabbitMQConsumer.java
index bda9900..4a0869f 100644
--- a/components/camel-rabbitmq/src/main/java/org/apache/camel/component/rabbitmq/RabbitMQConsumer.java
+++ b/components/camel-rabbitmq/src/main/java/org/apache/camel/component/rabbitmq/RabbitMQConsumer.java
@@ -24,7 +24,10 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import com.rabbitmq.client.AMQP;
 import com.rabbitmq.client.Connection;
+import com.rabbitmq.client.Envelope;
+import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.Suspendable;
 import org.apache.camel.support.DefaultConsumer;
@@ -126,6 +129,13 @@ public class RabbitMQConsumer extends DefaultConsumer implements Suspendable {
         this.consumers.add(consumer);
     }
 
+    public Exchange createExchange(Envelope envelope, AMQP.BasicProperties properties, byte[] body) {
+        Exchange exchange = createExchange(false);
+        endpoint.getMessageConverter().populateRabbitExchange(exchange, envelope, properties, body, false,
+                endpoint.isAllowMessageBodySerialization());
+        return exchange;
+    }
+
     private synchronized void reconnect() {
         if (startConsumerCallable != null) {
             return;
diff --git a/components/camel-rabbitmq/src/test/java/org/apache/camel/component/rabbitmq/RabbitMQConsumerTest.java b/components/camel-rabbitmq/src/test/java/org/apache/camel/component/rabbitmq/RabbitMQConsumerTest.java
index a281bc3..5ec8688 100644
--- a/components/camel-rabbitmq/src/test/java/org/apache/camel/component/rabbitmq/RabbitMQConsumerTest.java
+++ b/components/camel-rabbitmq/src/test/java/org/apache/camel/component/rabbitmq/RabbitMQConsumerTest.java
@@ -24,7 +24,10 @@ import com.rabbitmq.client.AlreadyClosedException;
 import com.rabbitmq.client.Channel;
 import com.rabbitmq.client.Connection;
 import com.rabbitmq.client.Consumer;
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Processor;
+import org.apache.camel.spi.ExchangeFactory;
+import org.apache.camel.spi.ExecutorServiceManager;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 
@@ -33,24 +36,35 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
 
 public class RabbitMQConsumerTest {
 
+    private ExtendedCamelContext ecc = Mockito.mock(ExtendedCamelContext.class);
+    private ExchangeFactory ef = Mockito.mock(ExchangeFactory.class);
     private RabbitMQEndpoint endpoint = Mockito.mock(RabbitMQEndpoint.class);
     private Connection conn = Mockito.mock(Connection.class);
     private Processor processor = Mockito.mock(Processor.class);
     private Channel channel = Mockito.mock(Channel.class);
+    private ExecutorServiceManager esm = Mockito.mock(ExecutorServiceManager.class);
 
     @Test
     public void testStoppingConsumerShutdownExecutor() throws Exception {
-        RabbitMQConsumer consumer = new RabbitMQConsumer(endpoint, processor);
-
         ThreadPoolExecutor e = (ThreadPoolExecutor) Executors.newFixedThreadPool(3);
+
         Mockito.when(endpoint.createExecutor()).thenReturn(e);
         Mockito.when(endpoint.getConcurrentConsumers()).thenReturn(1);
         Mockito.when(endpoint.connect(any(ExecutorService.class))).thenReturn(conn);
+        Mockito.when(endpoint.getCamelContext()).thenReturn(ecc);
+        Mockito.when(ecc.adapt(ExtendedCamelContext.class)).thenReturn(ecc);
+        Mockito.when(ecc.getExchangeFactory()).thenReturn(ef);
+        Mockito.when(ef.newExchangeFactory(any())).thenReturn(ef);
+        Mockito.when(ecc.getExecutorServiceManager()).thenReturn(esm);
+        Mockito.when(esm.shutdownNow(e)).then(i -> e.shutdownNow());
         Mockito.when(conn.createChannel()).thenReturn(channel);
 
+        RabbitMQConsumer consumer = new RabbitMQConsumer(endpoint, processor);
+
         consumer.doStart();
         assertFalse(e.isShutdown());
 
@@ -60,13 +74,20 @@ public class RabbitMQConsumerTest {
 
     @Test
     public void testStoppingConsumerShutdownConnection() throws Exception {
-        RabbitMQConsumer consumer = new RabbitMQConsumer(endpoint, processor);
+        ExecutorService es = Executors.newFixedThreadPool(3);
 
-        Mockito.when(endpoint.createExecutor()).thenReturn(Executors.newFixedThreadPool(3));
+        Mockito.when(endpoint.createExecutor()).thenReturn(es);
         Mockito.when(endpoint.getConcurrentConsumers()).thenReturn(1);
         Mockito.when(endpoint.connect(any(ExecutorService.class))).thenReturn(conn);
         Mockito.when(conn.createChannel()).thenReturn(channel);
+        Mockito.when(endpoint.getCamelContext()).thenReturn(ecc);
+        Mockito.when(ecc.adapt(ExtendedCamelContext.class)).thenReturn(ecc);
+        Mockito.when(ecc.getExchangeFactory()).thenReturn(ef);
+        Mockito.when(ef.newExchangeFactory(any())).thenReturn(ef);
+        Mockito.when(ecc.getExecutorServiceManager()).thenReturn(esm);
+        Mockito.when(esm.shutdownNow(es)).then(i -> es.shutdownNow());
 
+        RabbitMQConsumer consumer = new RabbitMQConsumer(endpoint, processor);
         consumer.doStart();
         consumer.doStop();
 
@@ -76,18 +97,25 @@ public class RabbitMQConsumerTest {
     @Test
     public void testStoppingConsumerShutdownConnectionWhenServerHasClosedChannel() throws Exception {
         AlreadyClosedException alreadyClosedException = Mockito.mock(AlreadyClosedException.class);
+        ExecutorService es = Executors.newFixedThreadPool(3);
 
-        RabbitMQConsumer consumer = new RabbitMQConsumer(endpoint, processor);
-
-        Mockito.when(endpoint.createExecutor()).thenReturn(Executors.newFixedThreadPool(3));
+        Mockito.when(endpoint.createExecutor()).thenReturn(es);
         Mockito.when(endpoint.getConcurrentConsumers()).thenReturn(1);
         Mockito.when(endpoint.connect(any(ExecutorService.class))).thenReturn(conn);
         Mockito.when(conn.createChannel()).thenReturn(channel);
         Mockito.when(channel.basicConsume(anyString(), anyBoolean(), any(Consumer.class))).thenReturn("TAG");
         Mockito.when(channel.isOpen()).thenReturn(false);
+        Mockito.when(endpoint.getCamelContext()).thenReturn(ecc);
+        Mockito.when(ecc.adapt(ExtendedCamelContext.class)).thenReturn(ecc);
+        Mockito.when(ecc.getExchangeFactory()).thenReturn(ef);
+        Mockito.when(ef.newExchangeFactory(any())).thenReturn(ef);
+        Mockito.when(ecc.getExecutorServiceManager()).thenReturn(esm);
+        Mockito.when(esm.shutdownNow(es)).then(i -> es.shutdownNow());
+
         Mockito.doThrow(alreadyClosedException).when(channel).basicCancel("TAG");
         Mockito.doThrow(alreadyClosedException).when(channel).close();
 
+        RabbitMQConsumer consumer = new RabbitMQConsumer(endpoint, processor);
         consumer.doStart();
         consumer.doStop();
 
diff --git a/components/camel-reactive-streams/src/main/java/org/apache/camel/component/reactive/streams/ReactiveStreamsConsumer.java b/components/camel-reactive-streams/src/main/java/org/apache/camel/component/reactive/streams/ReactiveStreamsConsumer.java
index 989b901..815c3e2 100644
--- a/components/camel-reactive-streams/src/main/java/org/apache/camel/component/reactive/streams/ReactiveStreamsConsumer.java
+++ b/components/camel-reactive-streams/src/main/java/org/apache/camel/component/reactive/streams/ReactiveStreamsConsumer.java
@@ -75,7 +75,7 @@ public class ReactiveStreamsConsumer extends DefaultConsumer {
 
     public void onComplete() {
         if (endpoint.isForwardOnComplete()) {
-            Exchange exchange = endpoint.createExchange();
+            Exchange exchange = createExchange(true);
             exchange.getIn().setHeader(ReactiveStreamsConstants.REACTIVE_STREAMS_EVENT_TYPE, "onComplete");
 
             doSend(exchange, done -> {
@@ -85,7 +85,7 @@ public class ReactiveStreamsConsumer extends DefaultConsumer {
 
     public void onError(Throwable error) {
         if (endpoint.isForwardOnError()) {
-            Exchange exchange = endpoint.createExchange();
+            Exchange exchange = createExchange(true);
             exchange.getIn().setHeader(ReactiveStreamsConstants.REACTIVE_STREAMS_EVENT_TYPE, "onError");
             exchange.getIn().setBody(error);
 
diff --git a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceConsumer.java b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceConsumer.java
index 5299505..5f60fb1 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceConsumer.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceConsumer.java
@@ -142,7 +142,7 @@ public class SalesforceConsumer extends DefaultConsumer {
             LOG.debug("Received event {} on channel {}", channel.getId(), channel.getChannelId());
         }
 
-        final Exchange exchange = endpoint.createExchange();
+        final Exchange exchange = createExchange(false);
         final org.apache.camel.Message in = exchange.getIn();
 
         switch (messageKind) {
@@ -179,6 +179,7 @@ public class SalesforceConsumer extends DefaultConsumer {
                 final String msg = String.format("Unhandled exception: %s", ex.getMessage());
                 handleException(msg, new SalesforceException(msg, ex));
             }
+            releaseExchange(exchange, false);
         }
     }
 
diff --git a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceConsumerTest.java b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceConsumerTest.java
index 29c8e60..603e5db 100644
--- a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceConsumerTest.java
+++ b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceConsumerTest.java
@@ -25,10 +25,12 @@ import java.util.Objects;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import org.apache.camel.AsyncProcessor;
 import org.apache.camel.CamelContext;
-import org.apache.camel.Exchange;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.ExtendedExchange;
 import org.apache.camel.component.salesforce.api.dto.PlatformEvent;
 import org.apache.camel.component.salesforce.internal.streaming.SubscriptionHelper;
 import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.spi.ExchangeFactory;
 import org.cometd.bayeux.Message;
 import org.cometd.bayeux.client.ClientSessionChannel;
 import org.cometd.common.HashMapMessage;
@@ -82,9 +84,11 @@ public class SalesforceConsumerTest {
 
     SalesforceEndpointConfig configuration = new SalesforceEndpointConfig();
     SalesforceEndpoint endpoint = mock(SalesforceEndpoint.class);
-    Exchange exchange = mock(Exchange.class);
+    ExtendedExchange exchange = mock(ExtendedExchange.class);
     org.apache.camel.Message in = mock(org.apache.camel.Message.class);
     AsyncProcessor processor = mock(AsyncProcessor.class);
+    ExtendedCamelContext context = mock(ExtendedCamelContext.class);
+    ExchangeFactory exchangeFactory = mock(ExchangeFactory.class);
     Message pushTopicMessage;
 
     @Mock
@@ -99,7 +103,12 @@ public class SalesforceConsumerTest {
     @BeforeEach
     public void setupMocks() {
         when(endpoint.getConfiguration()).thenReturn(configuration);
-        when(endpoint.createExchange()).thenReturn(exchange);
+        when(endpoint.getCamelContext()).thenReturn(context);
+        when(context.adapt(ExtendedCamelContext.class)).thenReturn(context);
+        when(context.getExchangeFactory()).thenReturn(exchangeFactory);
+        when(exchangeFactory.newExchangeFactory(any())).thenReturn(exchangeFactory);
+        when(exchangeFactory.create(endpoint, false)).thenReturn(exchange);
+        when(exchange.adapt(ExtendedExchange.class)).thenReturn(exchange);
         when(exchange.getIn()).thenReturn(in);
         final SalesforceComponent component = mock(SalesforceComponent.class);
         when(endpoint.getComponent()).thenReturn(component);
diff --git a/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerConsumer.java b/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerConsumer.java
index 240e673..3ddbf44 100644
--- a/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerConsumer.java
+++ b/components/camel-scheduler/src/main/java/org/apache/camel/component/scheduler/SchedulerConsumer.java
@@ -17,8 +17,8 @@
 package org.apache.camel.component.scheduler;
 
 import java.util.Date;
+import java.util.concurrent.atomic.AtomicBoolean;
 
-import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.support.ScheduledPollConsumer;
@@ -44,7 +44,7 @@ public class SchedulerConsumer extends ScheduledPollConsumer {
     }
 
     protected int sendTimerExchange() {
-        final Exchange exchange = getEndpoint().createExchange();
+        final Exchange exchange = createExchange(false);
         exchange.setProperty(Exchange.TIMER_NAME, getEndpoint().getName());
 
         Date now = new Date();
@@ -55,15 +55,25 @@ public class SchedulerConsumer extends ScheduledPollConsumer {
         }
 
         if (!getEndpoint().isSynchronous()) {
-            getAsyncProcessor().process(exchange, new AsyncCallback() {
-                @Override
-                public void done(boolean doneSync) {
-                    // handle any thrown exception
-                    if (exchange.getException() != null) {
-                        getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
-                    }
+            final AtomicBoolean polled = new AtomicBoolean(true);
+            boolean doneSync = getAsyncProcessor().process(exchange, cbDoneSync -> {
+                // handle any thrown exception
+                if (exchange.getException() != null) {
+                    getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
+                }
+                boolean wasPolled = exchange.getProperty(Exchange.SCHEDULER_POLLED_MESSAGES, true, boolean.class);
+                if (!wasPolled) {
+                    polled.set(false);
+                }
+
+                // sync wil release outside this callback
+                if (!cbDoneSync) {
+                    releaseExchange(exchange, false);
                 }
             });
+            if (!doneSync) {
+                return polled.get() ? 1 : 0;
+            }
         } else {
             try {
                 getProcessor().process(exchange);
@@ -81,6 +91,7 @@ public class SchedulerConsumer extends ScheduledPollConsumer {
         // for example to overrule and indicate no message was polled, which can affect the scheduler
         // to leverage backoff on idle etc.
         boolean polled = exchange.getProperty(Exchange.SCHEDULER_POLLED_MESSAGES, true, boolean.class);
+        releaseExchange(exchange, false);
         return polled ? 1 : 0;
     }
 
diff --git a/components/camel-sip/src/main/java/org/apache/camel/component/sip/listener/SipSubscriptionListener.java b/components/camel-sip/src/main/java/org/apache/camel/component/sip/listener/SipSubscriptionListener.java
index 7951940..2392eb6 100644
--- a/components/camel-sip/src/main/java/org/apache/camel/component/sip/listener/SipSubscriptionListener.java
+++ b/components/camel-sip/src/main/java/org/apache/camel/component/sip/listener/SipSubscriptionListener.java
@@ -31,7 +31,6 @@ import javax.sip.header.ViaHeader;
 import javax.sip.message.Request;
 import javax.sip.message.Response;
 
-import org.apache.camel.CamelException;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
 import org.apache.camel.component.sip.SipSubscriber;
@@ -48,14 +47,15 @@ public class SipSubscriptionListener implements SipListener {
         this.setSipSubscriber(sipSubscriber);
     }
 
-    private void dispatchExchange(Object response) throws CamelException {
+    private void dispatchExchange(Object response) {
         LOG.debug("Consumer Dispatching the received notification along the route");
-        Exchange exchange = sipSubscriber.getEndpoint().createExchange(ExchangePattern.InOnly);
+        Exchange exchange = sipSubscriber.createExchange(true);
+        exchange.setPattern(ExchangePattern.InOnly);
         exchange.getIn().setBody(response);
         try {
             sipSubscriber.getProcessor().process(exchange);
         } catch (Exception e) {
-            throw new CamelException("Error in consumer while dispatching exchange", e);
+            sipSubscriber.getExceptionHandler().handleException("Error in consumer while dispatching exchange", e);
         }
     }
 
diff --git a/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/SjmsEndpoint.java b/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/SjmsEndpoint.java
index d8e1bee..c65df4f 100644
--- a/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/SjmsEndpoint.java
+++ b/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/SjmsEndpoint.java
@@ -318,13 +318,13 @@ public class SjmsEndpoint extends DefaultEndpoint
 
     @Override
     public Consumer createConsumer(Processor processor) throws Exception {
-        EndpointMessageListener listener = new EndpointMessageListener(this, processor);
-        configureMessageListener(listener);
-
         MessageListenerContainer container = createMessageListenerContainer(this);
+        SjmsConsumer consumer = new SjmsConsumer(this, processor, container);
+
+        EndpointMessageListener listener = new EndpointMessageListener(consumer, this, processor);
+        configureMessageListener(listener);
         container.setMessageListener(listener);
 
-        SjmsConsumer consumer = new SjmsConsumer(this, processor, container);
         configureConsumer(consumer);
         return consumer;
     }
diff --git a/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/SjmsMessage.java b/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/SjmsMessage.java
index 35f066e..2f76d12 100644
--- a/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/SjmsMessage.java
+++ b/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/SjmsMessage.java
@@ -53,6 +53,14 @@ public class SjmsMessage extends DefaultMessage {
     }
 
     @Override
+    public void reset() {
+        super.reset();
+        jmsMessage = null;
+        jmsSession = null;
+        binding = null;
+    }
+
+    @Override
     public String toString() {
         // do not print jmsMessage as there could be sensitive details
         if (jmsMessage != null) {
diff --git a/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/consumer/EndpointMessageListener.java b/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/consumer/EndpointMessageListener.java
index 8c7b9d3..b2c9515 100644
--- a/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/consumer/EndpointMessageListener.java
+++ b/components/camel-sjms/src/main/java/org/apache/camel/component/sjms/consumer/EndpointMessageListener.java
@@ -29,13 +29,16 @@ import org.apache.camel.AsyncProcessor;
 import org.apache.camel.CamelExchangeException;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
+import org.apache.camel.ExtendedExchange;
 import org.apache.camel.Processor;
 import org.apache.camel.RollbackExchangeException;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.sjms.SessionCallback;
 import org.apache.camel.component.sjms.SessionMessageListener;
 import org.apache.camel.component.sjms.SjmsConstants;
+import org.apache.camel.component.sjms.SjmsConsumer;
 import org.apache.camel.component.sjms.SjmsEndpoint;
+import org.apache.camel.component.sjms.SjmsMessage;
 import org.apache.camel.component.sjms.SjmsTemplate;
 import org.apache.camel.component.sjms.jms.JmsMessageHelper;
 import org.apache.camel.support.AsyncProcessorConverterHelper;
@@ -54,6 +57,7 @@ public class EndpointMessageListener implements SessionMessageListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(EndpointMessageListener.class);
 
+    private final SjmsConsumer consumer;
     private final SjmsEndpoint endpoint;
     private final AsyncProcessor processor;
     private Object replyToDestination;
@@ -63,7 +67,8 @@ public class EndpointMessageListener implements SessionMessageListener {
     private String eagerPoisonBody;
     private volatile SjmsTemplate template;
 
-    public EndpointMessageListener(SjmsEndpoint endpoint, Processor processor) {
+    public EndpointMessageListener(SjmsConsumer consumer, SjmsEndpoint endpoint, Processor processor) {
+        this.consumer = consumer;
         this.endpoint = endpoint;
         this.processor = AsyncProcessorConverterHelper.convert(processor);
     }
@@ -207,6 +212,9 @@ public class EndpointMessageListener implements SessionMessageListener {
             // if we failed processed the exchange from the async callback task, then grab the exception
             rce = exchange.getException(RuntimeCamelException.class);
 
+            // the exchange is now done so release it
+            consumer.releaseExchange(exchange, false);
+
         } catch (Exception e) {
             rce = wrapRuntimeCamelException(e);
         }
@@ -234,7 +242,18 @@ public class EndpointMessageListener implements SessionMessageListener {
     }
 
     public Exchange createExchange(Message message, Session session, Object replyDestination) {
-        Exchange exchange = endpoint.createExchange(message, session);
+        Exchange exchange = consumer.createExchange(false);
+
+        // optimize: either create a new SjmsMessage or reuse existing if exists
+        SjmsMessage msg = exchange.adapt(ExtendedExchange.class).getInOrNull(SjmsMessage.class);
+        if (msg == null) {
+            msg = new SjmsMessage(exchange, message, session, endpoint.getBinding());
+            exchange.setIn(msg);
+        } else {
+            msg.setJmsMessage(message);
+            msg.setJmsSession(session);
+            msg.setBinding(endpoint.getBinding());
+        }
 
         // lets set to an InOut if we have some kind of reply-to destination
         if (replyDestination != null && !disableReplyTo) {
@@ -455,6 +474,12 @@ public class EndpointMessageListener implements SessionMessageListener {
                     }
                 }
             }
+
+            // if we completed from async processing then we should release the exchange
+            // the sync processing will release the exchange outside this callback
+            if (!doneSync) {
+                consumer.releaseExchange(exchange, false);
+            }
         }
     }
 
diff --git a/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyConsumerQueueTest.java b/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyConsumerQueueTest.java
index b55fec2..af55fc2 100644
--- a/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyConsumerQueueTest.java
+++ b/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyConsumerQueueTest.java
@@ -38,6 +38,17 @@ public class InOnlyConsumerQueueTest extends JmsTestSupport {
         mock.assertIsSatisfied();
     }
 
+    @Test
+    public void testTwoSynchronous() throws Exception {
+        MockEndpoint mock = getMockEndpoint(MOCK_RESULT);
+        mock.expectedBodiesReceived("Hello World", "Bye World");
+
+        template.sendBody(SJMS_QUEUE_NAME, "Hello World");
+        template.sendBody(SJMS_QUEUE_NAME, "Bye World");
+
+        mock.assertIsSatisfied();
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
diff --git a/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyConsumerQueueTest.java b/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyPooledExchangeTest.java
similarity index 69%
copy from components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyConsumerQueueTest.java
copy to components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyPooledExchangeTest.java
index b55fec2..9ddbf05 100644
--- a/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyConsumerQueueTest.java
+++ b/components/camel-sjms/src/test/java/org/apache/camel/component/sjms/consumer/InOnlyPooledExchangeTest.java
@@ -16,16 +16,26 @@
  */
 package org.apache.camel.component.sjms.consumer;
 
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.apache.camel.component.sjms.support.JmsTestSupport;
+import org.apache.camel.impl.engine.PooledExchangeFactory;
 import org.junit.jupiter.api.Test;
 
-public class InOnlyConsumerQueueTest extends JmsTestSupport {
+public class InOnlyPooledExchangeTest extends JmsTestSupport {
 
     private static final String SJMS_QUEUE_NAME = "sjms:queue:in.only.consumer.queue";
     private static final String MOCK_RESULT = "mock:result";
 
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        context.adapt(ExtendedCamelContext.class).setExchangeFactory(new PooledExchangeFactory());
+        return context;
+    }
+
     @Test
     public void testSynchronous() throws Exception {
         final String expectedBody = "Hello World";
@@ -38,6 +48,17 @@ public class InOnlyConsumerQueueTest extends JmsTestSupport {
         mock.assertIsSatisfied();
     }
 
+    @Test
+    public void testTwoSynchronous() throws Exception {
+        MockEndpoint mock = getMockEndpoint(MOCK_RESULT);
+        mock.expectedBodiesReceived("Hello World", "Bye World");
+
+        template.sendBody(SJMS_QUEUE_NAME, "Hello World");
+        template.sendBody(SJMS_QUEUE_NAME, "Bye World");
+
+        mock.assertIsSatisfied();
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
diff --git a/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackConsumer.java b/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackConsumer.java
index 396e66e..fde7f10 100644
--- a/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackConsumer.java
+++ b/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackConsumer.java
@@ -25,8 +25,10 @@ import java.util.List;
 import java.util.Queue;
 
 import org.apache.camel.Exchange;
+import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.slack.helper.SlackMessage;
 import org.apache.camel.support.ScheduledBatchPollingConsumer;
 import org.apache.camel.util.CastUtils;
 import org.apache.camel.util.ObjectHelper;
@@ -109,7 +111,7 @@ public class SlackConsumer extends ScheduledBatchPollingConsumer {
                     timestamp = (String) singleMess.get("ts");
                 }
                 i++;
-                Exchange exchange = slackEndpoint.createExchange(singleMess);
+                Exchange exchange = createExchange(singleMess);
                 answer.add(exchange);
             }
         }
@@ -185,4 +187,22 @@ public class SlackConsumer extends ScheduledBatchPollingConsumer {
         }
     }
 
+    public Exchange createExchange(JsonObject object) {
+        Exchange exchange = createExchange(true);
+        SlackMessage slackMessage = new SlackMessage();
+        String text = object.getString(SlackConstants.SLACK_TEXT_FIELD);
+        String user = object.getString("user");
+        slackMessage.setText(text);
+        slackMessage.setUser(user);
+        if (ObjectHelper.isNotEmpty(object.get("icons"))) {
+            JsonObject icons = object.getMap("icons");
+            if (ObjectHelper.isNotEmpty(icons.get("emoji"))) {
+                slackMessage.setIconEmoji(icons.getString("emoji"));
+            }
+        }
+        Message message = exchange.getIn();
+        message.setBody(slackMessage);
+        return exchange;
+    }
+
 }
diff --git a/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackEndpoint.java b/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackEndpoint.java
index c5bf928..9893b21 100644
--- a/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackEndpoint.java
+++ b/components/camel-slack/src/main/java/org/apache/camel/component/slack/SlackEndpoint.java
@@ -18,20 +18,15 @@ package org.apache.camel.component.slack;
 
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
-import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.RuntimeCamelException;
-import org.apache.camel.component.slack.helper.SlackMessage;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
 import org.apache.camel.support.ScheduledPollEndpoint;
 import org.apache.camel.util.ObjectHelper;
-import org.apache.camel.util.json.JsonObject;
 
 /**
  * Send and receive messages to/from Slack.
@@ -183,25 +178,4 @@ public class SlackEndpoint extends ScheduledPollEndpoint {
         this.serverUrl = serverUrl;
     }
 
-    public Exchange createExchange(JsonObject object) {
-        return createExchange(getExchangePattern(), object);
-    }
-
-    public Exchange createExchange(ExchangePattern pattern, JsonObject object) {
-        Exchange exchange = super.createExchange(pattern);
-        SlackMessage slackMessage = new SlackMessage();
-        String text = object.getString(SlackConstants.SLACK_TEXT_FIELD);
-        String user = object.getString("user");
-        slackMessage.setText(text);
-        slackMessage.setUser(user);
-        if (ObjectHelper.isNotEmpty(object.get("icons"))) {
-            JsonObject icons = object.getMap("icons");
-            if (ObjectHelper.isNotEmpty(icons.get("emoji"))) {
-                slackMessage.setIconEmoji(icons.getString("emoji"));
-            }
-        }
-        Message message = exchange.getIn();
-        message.setBody(slackMessage);
-        return exchange;
-    }
 }
diff --git a/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/MessageReceiverListenerImpl.java b/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/MessageReceiverListenerImpl.java
index c076335..9eb4e2e 100644
--- a/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/MessageReceiverListenerImpl.java
+++ b/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/MessageReceiverListenerImpl.java
@@ -17,6 +17,7 @@
 package org.apache.camel.component.smpp;
 
 import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
 import org.apache.camel.Processor;
 import org.apache.camel.spi.ExceptionHandler;
 import org.jsmpp.bean.AlertNotification;
@@ -37,11 +38,14 @@ public class MessageReceiverListenerImpl implements MessageReceiverListener {
     private static final Logger LOG = LoggerFactory.getLogger(MessageReceiverListenerImpl.class);
 
     private MessageIDGenerator messageIDGenerator = new RandomMessageIDGenerator();
+    private SmppConsumer consumer;
     private SmppEndpoint endpoint;
     private Processor processor;
     private ExceptionHandler exceptionHandler;
 
-    public MessageReceiverListenerImpl(SmppEndpoint endpoint, Processor processor, ExceptionHandler exceptionHandler) {
+    public MessageReceiverListenerImpl(SmppConsumer consumer, SmppEndpoint endpoint, Processor processor,
+                                       ExceptionHandler exceptionHandler) {
+        this.consumer = consumer;
         this.endpoint = endpoint;
         this.processor = processor;
         this.exceptionHandler = exceptionHandler;
@@ -51,7 +55,7 @@ public class MessageReceiverListenerImpl implements MessageReceiverListener {
     public void onAcceptAlertNotification(AlertNotification alertNotification) {
         LOG.debug("Received an alertNotification {}", alertNotification);
 
-        Exchange exchange = endpoint.createOnAcceptAlertNotificationExchange(alertNotification);
+        Exchange exchange = createOnAcceptAlertNotificationExchange(alertNotification);
         try {
             processor.process(exchange);
         } catch (Exception e) {
@@ -62,6 +66,7 @@ public class MessageReceiverListenerImpl implements MessageReceiverListener {
             exceptionHandler.handleException("Cannot process exchange. This exception will be ignored.", exchange,
                     exchange.getException());
         }
+        consumer.releaseExchange(exchange, false);
     }
 
     @Override
@@ -117,4 +122,19 @@ public class MessageReceiverListenerImpl implements MessageReceiverListener {
     public void setMessageIDGenerator(MessageIDGenerator messageIDGenerator) {
         this.messageIDGenerator = messageIDGenerator;
     }
+
+    /**
+     * Create a new exchange for communicating with this endpoint from a SMSC with the specified {@link ExchangePattern}
+     * such as whether its going to be an {@link ExchangePattern#InOnly} or {@link ExchangePattern#InOut} exchange
+     *
+     * @param  alertNotification the received message from the SMSC
+     * @return                   a new exchange
+     */
+    public Exchange createOnAcceptAlertNotificationExchange(AlertNotification alertNotification) {
+        Exchange exchange = consumer.createExchange(false);
+        exchange.setProperty(Exchange.BINDING, endpoint.getBinding());
+        exchange.setIn(endpoint.getBinding().createSmppMessage(endpoint.getCamelContext(), alertNotification));
+        return exchange;
+    }
+
 }
diff --git a/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppConsumer.java b/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppConsumer.java
index dee6ec3..c04c7f1 100644
--- a/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppConsumer.java
+++ b/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppConsumer.java
@@ -72,7 +72,8 @@ public class SmppConsumer extends DefaultConsumer {
                 }
             }
         };
-        this.messageReceiverListener = new MessageReceiverListenerImpl(getEndpoint(), getProcessor(), getExceptionHandler());
+        this.messageReceiverListener
+                = new MessageReceiverListenerImpl(this, getEndpoint(), getProcessor(), getExceptionHandler());
     }
 
     @Override
diff --git a/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppEndpoint.java b/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppEndpoint.java
index f9751e0..6f3b6d2 100644
--- a/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppEndpoint.java
+++ b/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppEndpoint.java
@@ -26,7 +26,6 @@ import org.apache.camel.Producer;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.support.DefaultEndpoint;
-import org.jsmpp.bean.AlertNotification;
 import org.jsmpp.bean.DataSm;
 import org.jsmpp.bean.DeliverSm;
 
@@ -71,33 +70,6 @@ public class SmppEndpoint extends DefaultEndpoint {
     /**
      * Create a new exchange for communicating with this endpoint from a SMSC
      *
-     * @param  alertNotification the received message from the SMSC
-     * @return                   a new exchange
-     */
-    public Exchange createOnAcceptAlertNotificationExchange(AlertNotification alertNotification) {
-        return createOnAcceptAlertNotificationExchange(getExchangePattern(), alertNotification);
-    }
-
-    /**
-     * Create a new exchange for communicating with this endpoint from a SMSC with the specified {@link ExchangePattern}
-     * such as whether its going to be an {@link ExchangePattern#InOnly} or {@link ExchangePattern#InOut} exchange
-     *
-     * @param  exchangePattern   the message exchange pattern for the exchange
-     * @param  alertNotification the received message from the SMSC
-     * @return                   a new exchange
-     */
-    public Exchange createOnAcceptAlertNotificationExchange(
-            ExchangePattern exchangePattern,
-            AlertNotification alertNotification) {
-        Exchange exchange = createExchange(exchangePattern);
-        exchange.setProperty(Exchange.BINDING, getBinding());
-        exchange.setIn(getBinding().createSmppMessage(getCamelContext(), alertNotification));
-        return exchange;
-    }
-
-    /**
-     * Create a new exchange for communicating with this endpoint from a SMSC
-     *
      * @param  deliverSm the received message from the SMSC
      * @return           a new exchange
      */
diff --git a/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/MessageReceiverListenerImplTest.java b/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/MessageReceiverListenerImplTest.java
deleted file mode 100644
index a34f6c8..0000000
--- a/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/MessageReceiverListenerImplTest.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.smpp;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Processor;
-import org.apache.camel.spi.ExceptionHandler;
-import org.jsmpp.PDUStringException;
-import org.jsmpp.bean.AlertNotification;
-import org.jsmpp.bean.DataSm;
-import org.jsmpp.bean.DeliverSm;
-import org.jsmpp.bean.OptionalParameter;
-import org.jsmpp.session.DataSmResult;
-import org.jsmpp.session.SMPPSession;
-import org.jsmpp.util.MessageIDGenerator;
-import org.jsmpp.util.MessageId;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class MessageReceiverListenerImplTest {
-
-    private MessageReceiverListenerImpl listener;
-    private SmppEndpoint endpoint;
-    private Processor processor;
-    private ExceptionHandler exceptionHandler;
-
-    @BeforeEach
-    public void setUp() {
-        endpoint = mock(SmppEndpoint.class);
-        processor = mock(Processor.class);
-        exceptionHandler = mock(ExceptionHandler.class);
-
-        listener = new MessageReceiverListenerImpl(endpoint, processor, exceptionHandler);
-        listener.setMessageIDGenerator(new MessageIDGenerator() {
-            public MessageId newMessageId() {
-                try {
-                    return new MessageId("1");
-                } catch (PDUStringException e) {
-                    throw new RuntimeException(e);
-                }
-            }
-        });
-    }
-
-    @Test
-    public void onAcceptAlertNotificationSuccess() throws Exception {
-        AlertNotification alertNotification = mock(AlertNotification.class);
-        Exchange exchange = mock(Exchange.class);
-
-        when(endpoint.createOnAcceptAlertNotificationExchange(alertNotification))
-                .thenReturn(exchange);
-        when(exchange.getException()).thenReturn(null);
-
-        listener.onAcceptAlertNotification(alertNotification);
-
-        verify(endpoint).createOnAcceptAlertNotificationExchange(alertNotification);
-        verify(processor).process(exchange);
-    }
-
-    @Test
-    public void onAcceptDeliverSmException() throws Exception {
-        DeliverSm deliverSm = mock(DeliverSm.class);
-        Exchange exchange = mock(Exchange.class);
-
-        when(endpoint.createOnAcceptDeliverSmExchange(deliverSm))
-                .thenReturn(exchange);
-        when(exchange.getException()).thenReturn(null);
-
-        listener.onAcceptDeliverSm(deliverSm);
-
-        verify(endpoint).createOnAcceptDeliverSmExchange(deliverSm);
-        verify(processor).process(exchange);
-    }
-
-    @Test
-    public void onAcceptDataSmSuccess() throws Exception {
-        SMPPSession session = mock(SMPPSession.class);
-        DataSm dataSm = mock(DataSm.class);
-        Exchange exchange = mock(Exchange.class);
-        OptionalParameter[] optionalParameters = new OptionalParameter[] {};
-
-        when(endpoint.createOnAcceptDataSm(dataSm, "1"))
-                .thenReturn(exchange);
-        when(exchange.getException()).thenReturn(null);
-        when(dataSm.getOptionalParameters())
-                .thenReturn(optionalParameters);
-
-        DataSmResult result = listener.onAcceptDataSm(dataSm, session);
-
-        verify(endpoint).createOnAcceptDataSm(dataSm, "1");
-        verify(processor).process(exchange);
-
-        assertEquals("1", result.getMessageId());
-        assertSame(optionalParameters, result.getOptionalParameters());
-    }
-
-}
diff --git a/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/SmppConsumerTest.java b/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/SmppConsumerTest.java
index 6404991..2274dbd 100644
--- a/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/SmppConsumerTest.java
+++ b/components/camel-smpp/src/test/java/org/apache/camel/component/smpp/SmppConsumerTest.java
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.component.smpp;
 
+import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.Processor;
+import org.apache.camel.spi.ExchangeFactory;
 import org.jsmpp.bean.BindType;
 import org.jsmpp.bean.NumberingPlanIndicator;
 import org.jsmpp.bean.TypeOfNumber;
@@ -28,6 +30,7 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
@@ -39,6 +42,8 @@ import static org.mockito.Mockito.when;
  */
 public class SmppConsumerTest {
 
+    private ExchangeFactory exchangeFactory;
+    private ExtendedCamelContext context;
     private SmppConsumer consumer;
     private SmppEndpoint endpoint;
     private SmppConfiguration configuration;
@@ -51,10 +56,17 @@ public class SmppConsumerTest {
         configuration.setServiceType("CMT");
         configuration.setSystemType("cp");
         configuration.setPassword("password");
+        context = mock(ExtendedCamelContext.class);
+        exchangeFactory = mock(ExchangeFactory.class);
         endpoint = mock(SmppEndpoint.class);
         processor = mock(Processor.class);
         session = mock(SMPPSession.class);
 
+        when(endpoint.getCamelContext()).thenReturn(context);
+        when(context.adapt(ExtendedCamelContext.class)).thenReturn(context);
+        when(context.getExchangeFactory()).thenReturn(exchangeFactory);
+        when(exchangeFactory.newExchangeFactory(any())).thenReturn(exchangeFactory);
+
         // the construction of SmppConsumer will trigger the getCamelContext call
         consumer = new SmppConsumer(
                 endpoint,
diff --git a/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpEndpoint.java b/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpEndpoint.java
index 3cf11b7..69303b4 100644
--- a/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpEndpoint.java
+++ b/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpEndpoint.java
@@ -30,7 +30,6 @@ import org.apache.camel.spi.UriPath;
 import org.apache.camel.support.DefaultPollingEndpoint;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.snmp4j.CommandResponderEvent;
 import org.snmp4j.PDU;
 import org.snmp4j.mp.SnmpConstants;
 import org.snmp4j.security.SecurityLevel;
@@ -140,19 +139,6 @@ public class SnmpEndpoint extends DefaultPollingEndpoint {
     }
 
     /**
-     * creates an exchange for the given message
-     *
-     * @param  pdu   the pdu
-     * @param  event a snmp4j CommandResponderEvent
-     * @return       an exchange
-     */
-    public Exchange createExchange(PDU pdu, CommandResponderEvent event) {
-        Exchange exchange = super.createExchange();
-        exchange.setIn(new SnmpMessage(getCamelContext(), pdu, event));
-        return exchange;
-    }
-
-    /**
      * creates and configures the endpoint
      *
      * @throws     Exception if unable to setup connection
diff --git a/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpTrapConsumer.java b/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpTrapConsumer.java
index 4639e8c..0de0f65 100644
--- a/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpTrapConsumer.java
+++ b/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpTrapConsumer.java
@@ -137,7 +137,7 @@ public class SnmpTrapConsumer extends DefaultConsumer implements CommandResponde
         if (LOG.isDebugEnabled()) {
             LOG.debug("Received trap event for {} : {}", this.endpoint.getAddress(), pdu);
         }
-        Exchange exchange = endpoint.createExchange(pdu, event);
+        Exchange exchange = createExchange(pdu, event);
         try {
             getProcessor().process(exchange);
         } catch (Exception e) {
@@ -146,5 +146,20 @@ public class SnmpTrapConsumer extends DefaultConsumer implements CommandResponde
         if (exchange.getException() != null) {
             getExceptionHandler().handleException(exchange.getException());
         }
+        releaseExchange(exchange, false);
     }
+
+    /**
+     * creates an exchange for the given message
+     *
+     * @param  pdu   the pdu
+     * @param  event a snmp4j CommandResponderEvent
+     * @return       an exchange
+     */
+    public Exchange createExchange(PDU pdu, CommandResponderEvent event) {
+        Exchange exchange = createExchange(false);
+        exchange.setIn(new SnmpMessage(getEndpoint().getCamelContext(), pdu, event));
+        return exchange;
+    }
+
 }
diff --git a/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotAbstractConsumer.java b/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotAbstractConsumer.java
index fbff371..c9340e7 100644
--- a/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotAbstractConsumer.java
+++ b/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotAbstractConsumer.java
@@ -16,7 +16,6 @@
  */
 package org.apache.camel.component.soroushbot.component;
 
-import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -65,15 +64,6 @@ public abstract class SoroushBotAbstractConsumer extends DefaultConsumer impleme
         run();
     }
 
-    protected final void handleExceptionThrownWhileCreatingOrProcessingExchange(
-            Exchange exchange, SoroushMessage soroushMessage, Exception ex) {
-        //set originalMessage property to the created soroushMessage to let  Error Handler access the message
-        exchange.setProperty("OriginalMessage", soroushMessage);
-        //use this instead of handleException() to manually set the exchange.
-        getExceptionHandler().handleException("message can not be processed due to :" + ex.getMessage(), exchange, ex);
-
-    }
-
     /**
      * handle how processing of the exchange should be started
      *
@@ -142,25 +132,21 @@ public abstract class SoroushBotAbstractConsumer extends DefaultConsumer impleme
 
             @Override
             public void onEvent(EventSource eventSource, String id, String type, String data) {
-                Exchange exchange = endpoint.createExchange();
+                Exchange exchange = createExchange(false);
                 try {
                     SoroushMessage soroushMessage = objectMapper.readValue(data, SoroushMessage.class);
-                    try {
-                        exchange.getIn().setBody(soroushMessage);
-                        if (LOG.isDebugEnabled()) {
-                            LOG.debug("event data is: " + data);
-                        }
-                        // if autoDownload is true, download the resource if provided in the message
-                        if (endpoint.isAutoDownload()) {
-                            endpoint.handleDownloadFiles(soroushMessage);
-                        }
-                        //let each subclass decide how to start processing of each exchange
-                        sendExchange(exchange);
-                    } catch (Exception ex) {
-                        handleExceptionThrownWhileCreatingOrProcessingExchange(exchange, soroushMessage, ex);
+                    exchange.getIn().setBody(soroushMessage);
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("event data is: " + data);
+                    }
+                    // if autoDownload is true, download the resource if provided in the message
+                    if (endpoint.isAutoDownload()) {
+                        endpoint.handleDownloadFiles(soroushMessage);
                     }
-                } catch (IOException ex) {
-                    LOG.error("can not parse data due to following error", ex);
+                    //let each subclass decide how to start processing of each exchange
+                    sendExchange(exchange);
+                } catch (Exception ex) {
+                    getExceptionHandler().handleException(ex);
                 }
             }
 
diff --git a/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotMultiThreadConsumer.java b/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotMultiThreadConsumer.java
index 96cecac..4badfee 100644
--- a/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotMultiThreadConsumer.java
+++ b/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotMultiThreadConsumer.java
@@ -57,6 +57,7 @@ public class SoroushBotMultiThreadConsumer extends SoroushBotAbstractConsumer {
                     getExceptionHandler().handleException("Error processing exchange",
                             exchange, exchange.getException());
                 }
+                releaseExchange(exchange, false);
             });
         } catch (IllegalStateException ex) {
             throw new CongestionException(ex, exchange.getIn().getBody(SoroushMessage.class));
diff --git a/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotSingleThreadConsumer.java b/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotSingleThreadConsumer.java
index 5926b3b..1ed907c 100644
--- a/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotSingleThreadConsumer.java
+++ b/components/camel-soroush/src/main/java/org/apache/camel/component/soroushbot/component/SoroushBotSingleThreadConsumer.java
@@ -42,5 +42,6 @@ public class SoroushBotSingleThreadConsumer extends SoroushBotAbstractConsumer {
             getExceptionHandler().handleException("Error processing exchange",
                     exchange, exchange.getException());
         }
+        releaseExchange(exchange, false);
     }
 }
diff --git a/components/camel-splunk/src/main/java/org/apache/camel/component/splunk/SplunkConsumer.java b/components/camel-splunk/src/main/java/org/apache/camel/component/splunk/SplunkConsumer.java
index dca8f97..72834d2 100644
--- a/components/camel-splunk/src/main/java/org/apache/camel/component/splunk/SplunkConsumer.java
+++ b/components/camel-splunk/src/main/java/org/apache/camel/component/splunk/SplunkConsumer.java
@@ -66,28 +66,18 @@ public class SplunkConsumer extends ScheduledBatchPollingConsumer {
 
                     @Override
                     public void process(SplunkEvent splunkEvent) {
-                        final Exchange exchange = getEndpoint().createExchange();
+                        final Exchange exchange = createExchange(true);
                         Message message = exchange.getIn();
                         message.setBody(splunkEvent);
 
-                        try {
-                            LOG.trace("Processing exchange [{}]...", exchange);
-                            getAsyncProcessor().process(exchange, new AsyncCallback() {
-                                @Override
-                                public void done(boolean doneSync) {
-                                    LOG.trace("Done processing exchange [{}]...", exchange);
-                                }
-                            });
-                        } catch (Exception e) {
-                            exchange.setException(e);
-                        }
-                        if (exchange.getException() != null) {
-                            getExceptionHandler().handleException("Error processing exchange", exchange,
-                                    exchange.getException());
-                        }
-
+                        LOG.trace("Processing exchange [{}]...", exchange);
+                        getAsyncProcessor().process(exchange, new AsyncCallback() {
+                            @Override
+                            public void done(boolean doneSync) {
+                                LOG.trace("Done processing exchange [{}]...", exchange);
+                            }
+                        });
                     }
-
                 });
                 // Return 0: no exchanges returned by poll, as exchanges have been returned asynchronously
                 return 0;
@@ -107,7 +97,7 @@ public class SplunkConsumer extends ScheduledBatchPollingConsumer {
         LOG.trace("Received {} messages in this poll", splunkEvents.size());
         Queue<Exchange> answer = new LinkedList<>();
         for (SplunkEvent splunkEvent : splunkEvents) {
-            Exchange exchange = getEndpoint().createExchange();
+            Exchange exchange = createExchange(true);
             Message message = exchange.getIn();
             message.setBody(splunkEvent);
             answer.add(exchange);
diff --git a/components/camel-spring-integration/src/main/java/org/apache/camel/component/spring/integration/SpringIntegrationConsumer.java b/components/camel-spring-integration/src/main/java/org/apache/camel/component/spring/integration/SpringIntegrationConsumer.java
index 0649696..256f75c 100644
--- a/components/camel-spring-integration/src/main/java/org/apache/camel/component/spring/integration/SpringIntegrationConsumer.java
+++ b/components/camel-spring-integration/src/main/java/org/apache/camel/component/spring/integration/SpringIntegrationConsumer.java
@@ -18,6 +18,7 @@ package org.apache.camel.component.spring.integration;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
+import org.apache.camel.ExtendedExchange;
 import org.apache.camel.Processor;
 import org.apache.camel.spring.SpringCamelContext;
 import org.apache.camel.support.DefaultConsumer;
@@ -99,15 +100,23 @@ public class SpringIntegrationConsumer extends DefaultConsumer implements Messag
     public void handleMessage(org.springframework.messaging.Message<?> siInMessage) {
         // we received a message from spring integration
         // wrap that in a Camel Exchange and process it
-        Exchange exchange
-                = getEndpoint().createExchange(getEndpoint().isInOut() ? ExchangePattern.InOut : ExchangePattern.InOnly);
-        exchange.setIn(new SpringIntegrationMessage(exchange, siInMessage));
+        Exchange exchange = createExchange(false);
+        exchange.setPattern(getEndpoint().isInOut() ? ExchangePattern.InOut : ExchangePattern.InOnly);
+
+        // optimize and reuse exchange
+        SpringIntegrationMessage sim = exchange.adapt(ExtendedExchange.class).getInOrNull(SpringIntegrationMessage.class);
+        if (sim == null) {
+            exchange.setIn(new SpringIntegrationMessage(exchange, siInMessage));
+        } else {
+            sim.setMessage(siInMessage);
+        }
 
         // process the exchange
         try {
             getProcessor().process(exchange);
         } catch (Exception e) {
             getExceptionHandler().handleException("Error processing exchange", exchange, e);
+            releaseExchange(exchange, false);
             return;
         }
 
@@ -140,6 +149,8 @@ public class SpringIntegrationConsumer extends DefaultConsumer implements Messag
             org.springframework.messaging.Message<?> siOutMessage
                     = SpringIntegrationBinding.storeToSpringIntegrationMessage(exchange.getOut());
 
+            releaseExchange(exchange, false);
+
             // send the message to spring integration
             LOG.debug("Sending {} to ReplyChannel: {}", siOutMessage, reply);
             reply.send(siOutMessage);
diff --git a/components/camel-spring-integration/src/main/java/org/apache/camel/component/spring/integration/SpringIntegrationMessage.java b/components/camel-spring-integration/src/main/java/org/apache/camel/component/spring/integration/SpringIntegrationMessage.java
index d3ced2e..778b2bc 100644
--- a/components/camel-spring-integration/src/main/java/org/apache/camel/component/spring/integration/SpringIntegrationMessage.java
+++ b/components/camel-spring-integration/src/main/java/org/apache/camel/component/spring/integration/SpringIntegrationMessage.java
@@ -44,6 +44,12 @@ public class SpringIntegrationMessage extends DefaultMessage {
         this.siMessage = message;
     }
 
+    @Override
+    public void reset() {
+        super.reset();
+        siMessage = null;
+    }
+
     public void setMessage(org.springframework.messaging.Message<?> message) {
         this.siMessage = message;
     }
diff --git a/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/EndpointMessageListener.java b/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/EndpointMessageListener.java
index 186bde3..39a7f02 100644
--- a/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/EndpointMessageListener.java
+++ b/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/EndpointMessageListener.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.component.springrabbit;
 
+import java.util.Map;
+
 import com.rabbitmq.client.Channel;
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.AsyncProcessor;
@@ -32,6 +34,7 @@ import org.springframework.amqp.core.Message;
 import org.springframework.amqp.core.MessageProperties;
 import org.springframework.amqp.rabbit.core.RabbitTemplate;
 import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
+import org.springframework.amqp.support.converter.MessageConverter;
 
 import static org.apache.camel.RuntimeCamelException.wrapRuntimeCamelException;
 
@@ -39,15 +42,21 @@ public class EndpointMessageListener implements ChannelAwareMessageListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(EndpointMessageListener.class);
 
+    private final SpringRabbitMQConsumer consumer;
     private final SpringRabbitMQEndpoint endpoint;
     private final AsyncProcessor processor;
+    private final MessagePropertiesConverter messagePropertiesConverter;
+    private final MessageConverter messageConverter;
     private RabbitTemplate template;
     private boolean disableReplyTo;
     private boolean async;
 
-    public EndpointMessageListener(SpringRabbitMQEndpoint endpoint, Processor processor) {
+    public EndpointMessageListener(SpringRabbitMQConsumer consumer, SpringRabbitMQEndpoint endpoint, Processor processor) {
+        this.consumer = consumer;
         this.endpoint = endpoint;
         this.processor = AsyncProcessorConverterHelper.convert(processor);
+        this.messagePropertiesConverter = endpoint.getMessagePropertiesConverter();
+        this.messageConverter = endpoint.getMessageConverter();
     }
 
     public boolean isAsync() {
@@ -132,6 +141,9 @@ public class EndpointMessageListener implements ChannelAwareMessageListener {
             // if we failed processed the exchange from the async callback task, then grab the exception
             rce = exchange.getException(RuntimeCamelException.class);
 
+            // the exchange is now done so release it
+            consumer.releaseExchange(exchange, false);
+
         } catch (Exception e) {
             rce = wrapRuntimeCamelException(e);
         }
@@ -148,7 +160,18 @@ public class EndpointMessageListener implements ChannelAwareMessageListener {
     }
 
     protected Exchange createExchange(Message message, Channel channel, Object replyDestination) {
-        Exchange exchange = endpoint.createExchange(message);
+        Exchange exchange = consumer.createExchange(false);
+
+        Object body = messageConverter.fromMessage(message);
+        exchange.getMessage().setBody(body);
+
+        // TODO: optimize to use existing headers map
+        Map<String, Object> headers
+                = messagePropertiesConverter.fromMessageProperties(message.getMessageProperties(), exchange);
+        if (!headers.isEmpty()) {
+            exchange.getMessage().setHeaders(headers);
+        }
+
         exchange.setProperty(SpringRabbitMQConstants.CHANNEL, channel);
 
         // lets set to an InOut if we have some kind of reply-to destination
@@ -238,6 +261,12 @@ public class EndpointMessageListener implements ChannelAwareMessageListener {
                     }
                 }
             }
+
+            // if we completed from async processing then we should release the exchange
+            // the sync processing will release the exchange outside this callback
+            if (!doneSync) {
+                consumer.releaseExchange(exchange, false);
+            }
         }
 
         private void sendReply(Address replyDestination, Message message, Exchange exchange, org.apache.camel.Message out) {
diff --git a/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/RabbitMQConsumer.java b/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/SpringRabbitMQConsumer.java
similarity index 94%
rename from components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/RabbitMQConsumer.java
rename to components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/SpringRabbitMQConsumer.java
index 773a861..a1fa041 100644
--- a/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/RabbitMQConsumer.java
+++ b/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/SpringRabbitMQConsumer.java
@@ -27,15 +27,15 @@ import org.springframework.amqp.rabbit.connection.Connection;
 import org.springframework.amqp.rabbit.connection.RabbitUtils;
 import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer;
 
-public class RabbitMQConsumer extends DefaultConsumer implements Suspendable {
+public class SpringRabbitMQConsumer extends DefaultConsumer implements Suspendable {
 
-    private static final Logger LOG = LoggerFactory.getLogger(RabbitMQConsumer.class);
+    private static final Logger LOG = LoggerFactory.getLogger(SpringRabbitMQConsumer.class);
 
     private AbstractMessageListenerContainer listenerContainer;
     private volatile EndpointMessageListener messageListener;
     private volatile boolean initialized;
 
-    public RabbitMQConsumer(Endpoint endpoint, Processor processor, AbstractMessageListenerContainer listenerContainer) {
+    public SpringRabbitMQConsumer(Endpoint endpoint, Processor processor, AbstractMessageListenerContainer listenerContainer) {
         super(endpoint, processor);
         this.listenerContainer = listenerContainer;
         this.listenerContainer.setMessageListener(getEndpointMessageListener());
@@ -54,7 +54,7 @@ public class RabbitMQConsumer extends DefaultConsumer implements Suspendable {
     }
 
     protected void createMessageListener(SpringRabbitMQEndpoint endpoint, Processor processor) {
-        messageListener = new EndpointMessageListener(endpoint, processor);
+        messageListener = new EndpointMessageListener(this, endpoint, processor);
         endpoint.configureMessageListener(messageListener);
     }
 
diff --git a/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/SpringRabbitMQEndpoint.java b/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/SpringRabbitMQEndpoint.java
index 2c7e1ea..70b441b 100644
--- a/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/SpringRabbitMQEndpoint.java
+++ b/components/camel-spring-rabbitmq/src/main/java/org/apache/camel/component/springrabbit/SpringRabbitMQEndpoint.java
@@ -348,7 +348,7 @@ public class SpringRabbitMQEndpoint extends DefaultEndpoint implements AsyncEndp
     @Override
     public Consumer createConsumer(Processor processor) throws Exception {
         AbstractMessageListenerContainer listenerContainer = createMessageListenerContainer();
-        RabbitMQConsumer consumer = new RabbitMQConsumer(this, processor, listenerContainer);
+        SpringRabbitMQConsumer consumer = new SpringRabbitMQConsumer(this, processor, listenerContainer);
         configureConsumer(consumer);
         return consumer;
     }
diff --git a/components/camel-spring-rabbitmq/src/test/java/org/apache/camel/component/springrabbit/integration/RabbitMQConsumerPooledExchangeIntTest.java b/components/camel-spring-rabbitmq/src/test/java/org/apache/camel/component/springrabbit/integration/RabbitMQConsumerPooledExchangeIntTest.java
new file mode 100644
index 0000000..596547e
--- /dev/null
+++ b/components/camel-spring-rabbitmq/src/test/java/org/apache/camel/component/springrabbit/integration/RabbitMQConsumerPooledExchangeIntTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.springrabbit.integration;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.engine.PooledExchangeFactory;
+import org.junit.jupiter.api.Test;
+
+public class RabbitMQConsumerPooledExchangeIntTest extends AbstractRabbitMQIntTest {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext camelContext = super.createCamelContext();
+        camelContext.adapt(ExtendedCamelContext.class).setExchangeFactory(new PooledExchangeFactory());
+        return camelContext;
+    }
+
+    @Test
+    public void testConsumer() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hello World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied(30, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testConsumerTwo() throws Exception {
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hello World", "Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start", "Bye World");
+
+        assertMockEndpointsSatisfied(30, TimeUnit.SECONDS);
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .to("spring-rabbitmq:foo");
+
+                from("spring-rabbitmq:foo")
+                        .to("log:result")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConsumer.java b/components/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConsumer.java
index b6c85df..72da864 100644
--- a/components/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConsumer.java
+++ b/components/camel-spring-redis/src/main/java/org/apache/camel/component/redis/RedisConsumer.java
@@ -16,7 +16,6 @@
  */
 package org.apache.camel.component.redis;
 
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -73,13 +72,14 @@ public class RedisConsumer extends DefaultConsumer implements MessageListener {
     @Override
     public void onMessage(Message message, byte[] pattern) {
         try {
-            Exchange exchange = getEndpoint().createExchange();
+            Exchange exchange = createExchange(true);
             setChannel(exchange, message.getChannel());
             setPattern(exchange, pattern);
             setBody(exchange, message.getBody());
+
             getProcessor().process(exchange);
         } catch (Exception e) {
-            throw new RuntimeException(e);
+            getExceptionHandler().handleException("Error processing redis message", e);
         }
     }
 
@@ -95,7 +95,7 @@ public class RedisConsumer extends DefaultConsumer implements MessageListener {
         }
     }
 
-    private void setChannel(Exchange exchange, byte[] message) throws UnsupportedEncodingException {
+    private void setChannel(Exchange exchange, byte[] message) {
         if (message != null) {
             exchange.getIn().setHeader(RedisConstants.CHANNEL, new String(message, StandardCharsets.UTF_8));
         }
diff --git a/components/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceConsumer.java b/components/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceConsumer.java
index 9b12824..abebef4 100644
--- a/components/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceConsumer.java
+++ b/components/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceConsumer.java
@@ -28,9 +28,9 @@ import javax.xml.transform.Source;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
+import org.apache.camel.ExtendedExchange;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
-import org.apache.camel.attachment.AttachmentMessage;
 import org.apache.camel.attachment.DefaultAttachmentMessage;
 import org.apache.camel.support.DefaultConsumer;
 import org.springframework.ws.WebServiceMessage;
@@ -61,25 +61,32 @@ public class SpringWebserviceConsumer extends DefaultConsumer implements Message
      */
     @Override
     public void invoke(MessageContext messageContext) throws Exception {
-        Exchange exchange = getEndpoint().createExchange(ExchangePattern.InOptionalOut);
-        populateExchangeFromMessageContext(messageContext, exchange);
-
-        // populate camel exchange with breadcrumb from transport header        
-        populateExchangeWithBreadcrumbFromMessageContext(messageContext, exchange);
-
-        // start message processing
-        getProcessor().process(exchange);
-
-        if (exchange.getException() != null) {
-            throw exchange.getException();
-        } else if (exchange.getPattern().isOutCapable()) {
-            Message responseMessage = exchange.getMessage(Message.class);
-            if (responseMessage != null) {
-                Source responseBody = responseMessage.getBody(Source.class);
-                WebServiceMessage response = messageContext.getResponse();
-                configuration.getMessageFilter().filterConsumer(exchange, response);
-                toResult(responseBody, response.getPayloadResult());
+        Exchange exchange = createExchange(false);
+        try {
+            exchange.setPattern(ExchangePattern.InOptionalOut);
+            populateExchangeFromMessageContext(messageContext, exchange);
+
+            // populate camel exchange with breadcrumb from transport header
+            if (getEndpoint().getCamelContext().isUseBreadcrumb()) {
+                populateExchangeWithBreadcrumbFromMessageContext(messageContext, exchange);
             }
+
+            // start message processing
+            getProcessor().process(exchange);
+
+            if (exchange.getException() != null) {
+                throw exchange.getException();
+            } else if (exchange.getPattern().isOutCapable()) {
+                Message responseMessage = exchange.getMessage(Message.class);
+                if (responseMessage != null) {
+                    Source responseBody = responseMessage.getBody(Source.class);
+                    WebServiceMessage response = messageContext.getResponse();
+                    configuration.getMessageFilter().filterConsumer(exchange, response);
+                    toResult(responseBody, response.getPayloadResult());
+                }
+            }
+        } finally {
+            releaseExchange(exchange, false);
         }
     }
 
@@ -116,7 +123,9 @@ public class SpringWebserviceConsumer extends DefaultConsumer implements Message
         if (messageContext != null) {
             HttpServletRequest obj = (HttpServletRequest) messageContext.getProperty("transport.http.servletRequest");
             String breadcrumbId = obj.getHeader(Exchange.BREADCRUMB_ID);
-            exchange.getIn().setHeader(Exchange.BREADCRUMB_ID, breadcrumbId);
+            if (breadcrumbId != null) {
+                exchange.getIn().setHeader(Exchange.BREADCRUMB_ID, breadcrumbId);
+            }
         }
     }
 
@@ -125,10 +134,17 @@ public class SpringWebserviceConsumer extends DefaultConsumer implements Message
 
         // create inbound message
         WebServiceMessage request = messageContext.getRequest();
-        SpringWebserviceMessage inMessage = new SpringWebserviceMessage(exchange.getContext(), request);
-        exchange.setIn(inMessage);
-        extractSourceFromSoapHeader(inMessage.getHeaders(), request);
-        extractAttachmentsFromRequest(request, new DefaultAttachmentMessage(inMessage));
+
+        SpringWebserviceMessage swm = exchange.adapt(ExtendedExchange.class).getInOrNull(SpringWebserviceMessage.class);
+        if (swm == null) {
+            swm = new SpringWebserviceMessage(exchange.getContext(), request);
+            exchange.setIn(swm);
+        } else {
+            swm.setWebServiceMessage(request);
+        }
+
+        extractSourceFromSoapHeader(exchange.getIn().getHeaders(), request);
+        extractAttachmentsFromRequest(request, exchange);
     }
 
     private void populateExchangeWithPropertiesFromMessageContext(
@@ -181,12 +197,19 @@ public class SpringWebserviceConsumer extends DefaultConsumer implements Message
 
     private void extractAttachmentsFromRequest(
             final WebServiceMessage request,
-            final AttachmentMessage inMessage) {
+            final Exchange exchange) {
+
+        DefaultAttachmentMessage dam = null;
+
         if (request instanceof MimeMessage) {
             Iterator<Attachment> attachmentsIterator = ((MimeMessage) request).getAttachments();
             while (attachmentsIterator.hasNext()) {
                 Attachment attachment = attachmentsIterator.next();
-                inMessage.addAttachment(attachment.getContentId(), attachment.getDataHandler());
+                if (dam == null) {
+                    // this is just a wrapper which will set data on the IN
+                    dam = new DefaultAttachmentMessage(exchange.getIn());
+                }
+                dam.addAttachment(attachment.getContentId(), attachment.getDataHandler());
             }
         }
     }
diff --git a/components/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceMessage.java b/components/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceMessage.java
index 6101345..49274a4 100644
--- a/components/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceMessage.java
+++ b/components/camel-spring-ws/src/main/java/org/apache/camel/component/spring/ws/SpringWebserviceMessage.java
@@ -29,6 +29,12 @@ public class SpringWebserviceMessage extends DefaultMessage {
     }
 
     @Override
+    public void reset() {
+        super.reset();
+        webServiceMessage = null;
+    }
+
+    @Override
     protected Object createBody() {
         if (webServiceMessage != null) {
             return webServiceMessage.getPayloadSource();
diff --git a/components/camel-spring/src/main/java/org/apache/camel/component/cron/SpringCronConsumer.java b/components/camel-spring/src/main/java/org/apache/camel/component/cron/SpringCronConsumer.java
index 217d9e7..e60ad73 100644
--- a/components/camel-spring/src/main/java/org/apache/camel/component/cron/SpringCronConsumer.java
+++ b/components/camel-spring/src/main/java/org/apache/camel/component/cron/SpringCronConsumer.java
@@ -29,7 +29,7 @@ public class SpringCronConsumer extends ScheduledPollConsumer {
 
     @Override
     protected int poll() throws Exception {
-        Exchange exchange = getEndpoint().createExchange();
+        Exchange exchange = createExchange(true);
         getProcessor().process(exchange);
         return 1;
     }
diff --git a/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlConsumer.java b/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlConsumer.java
index 036e9b7..78635f4 100644
--- a/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlConsumer.java
+++ b/components/camel-sql/src/main/java/org/apache/camel/component/sql/SqlConsumer.java
@@ -25,7 +25,6 @@ import java.util.List;
 import java.util.Queue;
 
 import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
 import org.apache.camel.RollbackExchangeException;
@@ -231,7 +230,7 @@ public class SqlConsumer extends ScheduledBatchPollingConsumer {
     }
 
     protected Exchange createExchange(Object data) {
-        final Exchange exchange = getEndpoint().createExchange(ExchangePattern.InOnly);
+        final Exchange exchange = createExchange(false);
         Message msg = exchange.getIn();
         if (getEndpoint().getOutputHeader() != null) {
             msg.setHeader(getEndpoint().getOutputHeader(), data);
@@ -274,10 +273,12 @@ public class SqlConsumer extends ScheduledBatchPollingConsumer {
             if (getEndpoint().isTransacted() && exchange.isFailed()) {
                 // break out as we are transacted and should rollback
                 Exception cause = exchange.getException();
+                // must release exchange
+                releaseExchange(exchange, false);
                 if (cause != null) {
                     throw cause;
                 } else {
-                    throw new RollbackExchangeException("Rollback transaction due error processing exchange", exchange);
+                    throw new RollbackExchangeException("Rollback transaction due error processing exchange", null);
                 }
             }
 
@@ -306,6 +307,8 @@ public class SqlConsumer extends ScheduledBatchPollingConsumer {
                 } else {
                     handleException("Error executing onConsume/onConsumeFailed query " + sql, e);
                 }
+            } finally {
+                releaseExchange(exchange, false);
             }
         }
 
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConsumer.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConsumer.java
index 8f7c229..a4b29f1 100644
--- a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConsumer.java
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConsumer.java
@@ -56,22 +56,21 @@ public class SshConsumer extends ScheduledPollConsumer {
         }
 
         String command = endpoint.getPollCommand();
-        Exchange exchange = endpoint.createExchange();
-
-        String knownHostResource = endpoint.getKnownHostsResource();
-        if (knownHostResource != null) {
-            client.setServerKeyVerifier(new ResourceBasedSSHKeyVerifier(
-                    exchange.getContext(), knownHostResource,
-                    endpoint.isFailOnUnknownHost()));
-        }
+        Exchange exchange = createExchange(false);
+        try {
+            String knownHostResource = endpoint.getKnownHostsResource();
+            if (knownHostResource != null) {
+                client.setServerKeyVerifier(new ResourceBasedSSHKeyVerifier(
+                        exchange.getContext(), knownHostResource,
+                        endpoint.isFailOnUnknownHost()));
+            }
 
-        SshResult result = SshHelper.sendExecCommand(exchange.getIn().getHeaders(), command, endpoint, client);
+            SshResult result = SshHelper.sendExecCommand(exchange.getIn().getHeaders(), command, endpoint, client);
 
-        exchange.getIn().setBody(result.getStdout());
-        exchange.getIn().setHeader(SshResult.EXIT_VALUE, result.getExitValue());
-        exchange.getIn().setHeader(SshResult.STDERR, result.getStderr());
+            exchange.getIn().setBody(result.getStdout());
+            exchange.getIn().setHeader(SshResult.EXIT_VALUE, result.getExitValue());
+            exchange.getIn().setHeader(SshResult.STDERR, result.getStderr());
 
-        try {
             // send message to next processor in the route
             getProcessor().process(exchange);
             return 1; // number of messages polled
@@ -80,6 +79,7 @@ public class SshConsumer extends ScheduledPollConsumer {
             if (exchange.getException() != null) {
                 getExceptionHandler().handleException("Error processing exchange", exchange, exchange.getException());
             }
+            releaseExchange(exchange, false);
         }
     }
 }
diff --git a/components/camel-stomp/src/main/java/org/apache/camel/component/stomp/StompEndpoint.java b/components/camel-stomp/src/main/java/org/apache/camel/component/stomp/StompEndpoint.java
index e1143d6..d6f122d 100644
--- a/components/camel-stomp/src/main/java/org/apache/camel/component/stomp/StompEndpoint.java
+++ b/components/camel-stomp/src/main/java/org/apache/camel/component/stomp/StompEndpoint.java
@@ -133,13 +133,15 @@ public class StompEndpoint extends DefaultEndpoint implements AsyncEndpoint, Hea
                     @Override
                     public void onSuccess(StompFrame value) {
                         if (!consumers.isEmpty()) {
-                            Exchange exchange = createExchange();
-                            exchange.getIn().setBody(value.content());
-                            exchange.getIn().setHeaders(value.headerMap().entrySet().stream()
-                                    .collect(Collectors.toMap(e -> e.getKey().toString(), Map.Entry::getValue)));
                             for (StompConsumer consumer : consumers) {
+                                Exchange exchange = consumer.createExchange(false);
+                                exchange.getIn().setBody(value.content());
+                                exchange.getIn().setHeaders(value.headerMap().entrySet().stream()
+                                        .collect(Collectors.toMap(e -> e.getKey().toString(), Map.Entry::getValue)));
                                 consumer.processExchange(exchange);
+                                consumer.releaseExchange(exchange, false);
                             }
+
                         }
                     }
                 });
diff --git a/components/camel-stream/src/main/java/org/apache/camel/component/stream/StreamConsumer.java b/components/camel-stream/src/main/java/org/apache/camel/component/stream/StreamConsumer.java
index 8416abf..a88886a 100644
--- a/components/camel-stream/src/main/java/org/apache/camel/component/stream/StreamConsumer.java
+++ b/components/camel-stream/src/main/java/org/apache/camel/component/stream/StreamConsumer.java
@@ -237,7 +237,7 @@ public class StreamConsumer extends DefaultConsumer implements Runnable {
                 List<String> copy = new ArrayList<>(lines);
                 Object body = endpoint.getGroupStrategy().groupLines(copy);
                 // remember to inc index when we create an exchange
-                Exchange exchange = endpoint.createExchange(body, index++, last);
+                Exchange exchange = createExchange(body, index++, last);
 
... 4689 lines suppressed ...