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/08/03 14:09:27 UTC

[camel] branch main updated: CAMEL-16757: Route configuration for separated, reusable and shareable configuration across all DSLs (#5917)

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

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


The following commit(s) were added to refs/heads/main by this push:
     new 148ce23  CAMEL-16757: Route configuration for separated, reusable and shareable configuration across all DSLs (#5917)
148ce23 is described below

commit 148ce23162cd59b4c9548f00175f1749fac06d30
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Aug 3 16:09:03 2021 +0200

    CAMEL-16757: Route configuration for separated, reusable and shareable configuration across all DSLs (#5917)
---
 .../org/apache/camel/catalog/models.properties     |   3 +-
 .../apache/camel/catalog/models/camelContext.json  |   1 +
 .../camel/catalog/models/routeConfiguration.json   |  22 ++
 .../camel/catalog/models/routeConfigurations.json  |  16 ++
 .../camel/catalog/models/templateBeanFactory.json  |  17 --
 .../apache/camel/catalog/schemas/camel-spring.xsd  |  38 +++
 .../camel/cdi/xml/CamelContextFactoryBean.java     |  14 +
 .../camel/cdi/test/XmlRouteConfigurationTest.java  |  77 +++++
 .../resources/camel-context-routeConfiguration.xml |  49 ++++
 .../org/apache/camel/spring/xml/camelContext.json  |   1 +
 .../camel/spring/xml/CamelContextFactoryBean.java  |  18 ++
 .../spring/xml/handler/CamelNamespaceHandler.java  |   1 +
 ...gRoutesConfigurationBuilderIdOrPatternTest.java |  48 ++++
 ...ngRoutesConfigurationBuilderIdOrPatternTest.xml |  52 ++++
 .../apache/camel/test/junit5/CamelTestSupport.java |   8 +
 .../apache/camel/test/junit4/CamelTestSupport.java |  10 +-
 ...ZooKeeperServiceDiscoveryFactoryConfigurer.java |   6 +-
 .../main/java/org/apache/camel/CamelContext.java   |   8 +
 .../java/org/apache/camel/CamelContextAware.java   |   2 +-
 .../src/main/java/org/apache/camel/Route.java      |  11 +
 ...yLevel.java => RouteConfigurationsBuilder.java} |  20 +-
 .../java/org/apache/camel/StartupSummaryLevel.java |   1 +
 .../java/org/apache/camel/spi/RoutesLoader.java    |  19 +-
 .../camel/impl/engine/AbstractCamelContext.java    |  39 ++-
 .../org/apache/camel/impl/engine/DefaultRoute.java |   6 +
 .../engine/DefaultSupervisingRouteController.java  |  25 +-
 .../org/apache/camel/impl/DefaultCamelContext.java |  22 ++
 .../java/org/apache/camel/impl/DefaultModel.java   |  40 +++
 .../camel/impl/lw/LightweightCamelContext.java     |  22 ++
 .../impl/lw/LightweightRuntimeCamelContext.java    |   6 +
 .../services/org/apache/camel/model.properties     |   3 +-
 .../resources/org/apache/camel/model/jaxb.index    |   2 +
 .../org/apache/camel/model/routeConfiguration.json |  22 ++
 .../apache/camel/model/routeConfigurations.json    |  16 ++
 .../apache/camel/model/templateBeanFactory.json    |  17 --
 .../java/org/apache/camel/builder/AdviceWith.java  |   4 +
 .../org/apache/camel/builder/BuilderSupport.java   |  33 ++-
 .../apache/camel/builder/LambdaRouteBuilder.java   |   2 +-
 .../org/apache/camel/builder/RouteBuilder.java     |  35 ++-
 .../camel/builder/RouteConfigurationBuilder.java   |  91 ++++++
 .../main/java/org/apache/camel/model/Model.java    |  21 ++
 ...ainer.java => RouteConfigurationContainer.java} |  16 +-
 .../camel/model/RouteConfigurationDefinition.java  | 198 +++++++++++++
 ...ion.java => RouteConfigurationsDefinition.java} |  87 +++---
 .../org/apache/camel/model/RouteContainer.java     |   2 +-
 .../org/apache/camel/model/RouteDefinition.java    |  30 ++
 .../apache/camel/model/RouteTemplateContainer.java |   2 +-
 .../camel/model/RouteTemplatesDefinition.java      |   3 +-
 .../org/apache/camel/model/RoutesDefinition.java   |  52 +++-
 .../apache/camel/model/rest/RestsDefinition.java   |   3 +-
 .../org/apache/camel/reifier/RouteReifier.java     |   5 +-
 .../core/xml/AbstractCamelContextFactoryBean.java  |  45 ++-
 .../java/org/apache/camel/ContextTestSupport.java  |  13 +-
 .../RoutesConfigurationBuilderIdOrPatternTest.java | 243 ++++++++++++++++
 .../model/RoutesConfigurationBuilderTest.java      | 310 +++++++++++++++++++++
 ...outesConfigurationMultipleRouteBuilderTest.java |  65 +++++
 .../camel/model/RoutesConfigurationTest.java       |  59 ++++
 .../builder/endpoint/EndpointRouteBuilder.java     |   6 +-
 .../EndpointRouteConfigurationBuilder.java         |  91 ++++++
 .../endpoint/LambdaEndpointRouteBuilder.java}      |  10 +-
 .../endpoint/EndpointRoutesConfigurationTest.java  |  57 ++++
 .../endpoint/LambdaEndpointRouteBuilderTest.java   |  86 ++++++
 .../org/apache/camel/main/RoutesConfigurer.java    |  39 ++-
 .../api/management/mbean/ManagedRouteMBean.java    |   3 +
 .../camel/management/mbean/ManagedRoute.java       |  15 +-
 .../java/org/apache/camel/xml/in/ModelParser.java  |  48 ++++
 docs/user-manual/modules/ROOT/nav.adoc             |   1 +
 docs/user-manual/modules/ROOT/pages/index.adoc     |   1 +
 .../modules/ROOT/pages/route-configuration.adoc    | 294 +++++++++++++++++++
 .../dsl/support/RouteBuilderLoaderSupport.java     |   2 +
 .../camel/dsl/xml/io/XmlRoutesBuilderLoader.java   |  34 ++-
 .../dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java   |  13 +-
 .../camel-yaml-dsl-deserializers/pom.xml           |   2 +
 .../dsl/yaml/deserializers/CustomResolver.java     |   3 +
 .../RouteConfigurationDefinitionDeserializer.java  |  93 +++++++
 .../deserializers/RouteDefinitionDeserializer.java |   4 +
 .../src/generated/resources/camel-yaml-dsl.json    |  45 +++
 .../camel/dsl/yaml/YamlRoutesBuilderLoader.java    |  22 +-
 .../camel/dsl/yaml/RouteConfigurationTest.groovy   | 169 +++++++++++
 .../packaging/ModelXmlParserGeneratorMojo.java     |   4 +-
 80 files changed, 2836 insertions(+), 187 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
index d0d5f2f..e0d7e06 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties
@@ -145,6 +145,8 @@ rollback
 roundRobin
 route
 routeBuilder
+routeConfiguration
+routeConfigurations
 routeContext
 routeContextRef
 routeTemplate
@@ -187,7 +189,6 @@ syslog
 tarfile
 template
 templateBean
-templateBeanFactory
 templateParameter
 templateScript
 threadPool
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/camelContext.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/camelContext.json
index fb39212..9a6507f 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/camelContext.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/camelContext.json
@@ -80,6 +80,7 @@
     "interceptSendToEndpoint": { "kind": "element", "displayName": "Intercept Send To Endpoint", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptSendToEndpointDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Configuration of interceptors that triggers sending messages to endpoints." },
     "restConfiguration": { "kind": "element", "displayName": "Rest Configuration", "required": false, "type": "object", "javaType": "org.apache.camel.model.rest.RestConfigurationDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Configuration for rest-dsl" },
     "rest": { "kind": "element", "displayName": "Rest", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.rest.RestDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the rest services defined using the rest-dsl" },
+    "routeConfiguration": { "kind": "element", "displayName": "Route Configuration", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteConfigurationDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel route configurations" },
     "routeTemplate": { "kind": "element", "displayName": "Route Template", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteTemplateDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel route templates" },
     "route": { "kind": "element", "displayName": "Route", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel routes" },
     "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The id of this node" }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json
new file mode 100644
index 0000000..bdb0150
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfiguration.json
@@ -0,0 +1,22 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "routeConfiguration",
+    "title": "Route Configuration",
+    "description": "Reusable configuration for Camel route(s).",
+    "deprecated": false,
+    "label": "configuration",
+    "javaType": "org.apache.camel.model.RouteConfigurationDefinition",
+    "input": false,
+    "output": false
+  },
+  "properties": {
+    "intercept": { "kind": "element", "displayName": "Intercept", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Adds a route for an interceptor that intercepts every processing step." },
+    "interceptFrom": { "kind": "element", "displayName": "Intercept From", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptFromDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Adds a route for an interceptor that intercepts incoming messages on the given endpoint." },
+    "interceptSendToEndpoint": { "kind": "element", "displayName": "Intercept Send To Endpoint", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptSendToEndpointDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Applies a route for an interceptor if an exchange is send to the given endpoint" },
+    "onException": { "kind": "element", "displayName": "On Exception", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.OnExceptionDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Exception clause for catching certain exceptions and handling them." },
+    "onCompletion": { "kind": "element", "displayName": "On Completion", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.OnCompletionDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "On completion callback for doing custom routing when the org.apache.camel.Exchange is complete." },
+    "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+    "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
+  }
+}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfigurations.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfigurations.json
new file mode 100644
index 0000000..d9d128f
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/routeConfigurations.json
@@ -0,0 +1,16 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "routeConfigurations",
+    "title": "Route Configurations",
+    "description": "A series of route configurations",
+    "deprecated": false,
+    "label": "configuration",
+    "javaType": "org.apache.camel.model.RouteConfigurationsDefinition",
+    "input": false,
+    "output": false
+  },
+  "properties": {
+    
+  }
+}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBeanFactory.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBeanFactory.json
deleted file mode 100644
index 538a54b..0000000
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/templateBeanFactory.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "model": {
-    "kind": "model",
-    "name": "templateBeanFactory",
-    "title": "Template Bean Factory",
-    "description": "A route template bean factory (local bean)",
-    "deprecated": false,
-    "label": "configuration",
-    "javaType": "org.apache.camel.model.RouteTemplateBeanFactoryDefinition",
-    "input": false,
-    "output": false
-  },
-  "properties": {
-    "language": { "kind": "attribute", "displayName": "Language", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "bean", "groovy", "joor", "language", "mvel", "ognl" ], "deprecated": false, "autowired": false, "secret": false, "description": "The language to use for creating the bean (such as groovy, joor)" },
-    "script": { "kind": "value", "displayName": "Script", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The script to execute that creates the bean. If the script use the prefix resource: such as resource:classpath:com\/foo\/myscript.groovy, resource:file:\/var\/myscript.groovy, then its loaded from the external resource." }
-  }
-}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index 1e8e59c..359ec7d 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -1265,6 +1265,22 @@ To refer to a Java org.apache.camel.builder.RouteBuilder instance to use.
     </xs:annotation>
   </xs:element>
 
+  <xs:element name="routeConfiguration" type="tns:routeConfigurationDefinition">
+    <xs:annotation>
+      <xs:documentation xml:lang="en"><![CDATA[
+Reusable configuration for Camel route(s).
+      ]]></xs:documentation>
+    </xs:annotation>
+  </xs:element>
+
+  <xs:element name="routeConfigurations" type="tns:routeConfigurationsDefinition">
+    <xs:annotation>
+      <xs:documentation xml:lang="en"><![CDATA[
+A series of route configurations
+      ]]></xs:documentation>
+    </xs:annotation>
+  </xs:element>
+
   <xs:element name="routeContext" type="tns:camelRouteContextFactoryBean">
     <xs:annotation>
       <xs:documentation xml:lang="en"><![CDATA[
@@ -10611,6 +10627,26 @@ Reference to the route builder instance.
     </xs:complexContent>
   </xs:complexType>
 
+  <xs:complexType name="routeConfigurationDefinition">
+    <xs:complexContent>
+      <xs:extension base="tns:optionalIdentifiedDefinition">
+        <xs:sequence>
+          <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:intercept"/>
+          <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:interceptFrom"/>
+          <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:interceptSendToEndpoint"/>
+          <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:onException"/>
+          <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:onCompletion"/>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+
+  <xs:complexType name="routeConfigurationsDefinition">
+    <xs:sequence>
+      <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:routeConfiguration"/>
+    </xs:sequence>
+  </xs:complexType>
+
   <xs:complexType name="routeContextRefDefinition">
     <xs:sequence/>
     <xs:attribute name="ref" type="xs:string" use="required">
@@ -10743,6 +10779,7 @@ Whether message history is enabled on this route. Default value: true
           </xs:annotation>
         </xs:attribute>
         <xs:attribute name="rest" type="xs:boolean"/>
+        <xs:attribute name="routeConfigurationId" type="xs:string"/>
         <xs:attribute name="routePolicyRef" type="xs:string">
           <xs:annotation>
             <xs:documentation xml:lang="en"><![CDATA[
@@ -15066,6 +15103,7 @@ MicroProfile Circuit Breaker EIP configurations.
           <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:interceptSendToEndpoint"/>
           <xs:element minOccurs="0" ref="tns:restConfiguration"/>
           <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:rest"/>
+          <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:routeConfiguration"/>
           <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:routeTemplate"/>
           <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:route"/>
         </xs:sequence>
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
index 001012d..96b7170 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
@@ -59,6 +59,7 @@ import org.apache.camel.model.PackageScanDefinition;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RestContextRefDefinition;
 import org.apache.camel.model.RouteBuilderDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteContextRefDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteTemplateContextRefDefinition;
@@ -296,6 +297,9 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Def
     @XmlElement(name = "rest")
     private List<RestDefinition> rests = new ArrayList<>();
 
+    @XmlElement(name = "routeConfiguration")
+    private List<RouteConfigurationDefinition> routeConfigurations = new ArrayList<>();
+
     @XmlElement(name = "routeTemplate")
     private List<RouteTemplateDefinition> routeTemplates = new ArrayList<>();
 
@@ -492,6 +496,16 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Def
     }
 
     @Override
+    public List<RouteConfigurationDefinition> getRouteConfigurations() {
+        return routeConfigurations;
+    }
+
+    @Override
+    public void setRouteConfigurations(List<RouteConfigurationDefinition> routeConfigurations) {
+        this.routeConfigurations = routeConfigurations;
+    }
+
+    @Override
     public List<RouteTemplateDefinition> getRouteTemplates() {
         return routeTemplates;
     }
diff --git a/components/camel-cdi/src/test/java/org/apache/camel/cdi/test/XmlRouteConfigurationTest.java b/components/camel-cdi/src/test/java/org/apache/camel/cdi/test/XmlRouteConfigurationTest.java
new file mode 100644
index 0000000..7bbcb0d
--- /dev/null
+++ b/components/camel-cdi/src/test/java/org/apache/camel/cdi/test/XmlRouteConfigurationTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.cdi.test;
+
+import java.nio.file.Paths;
+
+import javax.inject.Inject;
+
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.cdi.CdiCamelExtension;
+import org.apache.camel.cdi.ImportResource;
+import org.apache.camel.cdi.Uri;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.fail;
+
+@RunWith(Arquillian.class)
+@ImportResource("imported-context.xml")
+public class XmlRouteConfigurationTest {
+
+    @Inject
+    private ProducerTemplate template;
+
+    @Inject
+    @Uri("mock:error")
+    private MockEndpoint mock;
+
+    @Deployment
+    public static Archive<?> deployment() {
+        return ShrinkWrap.create(JavaArchive.class)
+                // Camel CDI
+                .addPackage(CdiCamelExtension.class.getPackage())
+                // Test Camel XML
+                .addAsResource(
+                        Paths.get("src/test/resources/camel-context-routeConfiguration.xml").toFile(),
+                        "imported-context.xml")
+                // Bean archive deployment descriptor
+                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
+    }
+
+    @Test
+    public void testRoutesConfigurationOnException() throws Exception {
+        mock.expectedBodiesReceived("Bye World");
+
+        try {
+            template.sendBody("direct:start", "Hello World");
+            fail("Should throw exception");
+        } catch (Exception e) {
+            // expected
+        }
+        template.sendBody("direct:start2", "Bye World");
+
+        mock.assertIsSatisfied();
+    }
+}
diff --git a/components/camel-cdi/src/test/resources/camel-context-routeConfiguration.xml b/components/camel-cdi/src/test/resources/camel-context-routeConfiguration.xml
new file mode 100644
index 0000000..a77cae3
--- /dev/null
+++ b/components/camel-cdi/src/test/resources/camel-context-routeConfiguration.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
+
+    <camelContext xmlns="http://camel.apache.org/schema/spring">
+
+        <routeConfiguration id="handleError">
+            <onException>
+                <exception>java.lang.Exception</exception>
+                <handled>
+                    <constant>true</constant>
+                </handled>
+                <to uri="mock:error"/>
+            </onException>
+        </routeConfiguration>
+
+        <route>
+            <from uri="direct:start"/>
+            <throwException exceptionType="java.lang.IllegalArgumentException" message="Foo"/>
+        </route>
+
+        <route routeConfigurationId="handleError">
+            <from uri="direct:start2"/>
+            <throwException exceptionType="java.lang.IllegalArgumentException" message="Foo2"/>
+        </route>
+
+    </camelContext>
+
+</beans>
diff --git a/components/camel-spring-xml/src/generated/resources/org/apache/camel/spring/xml/camelContext.json b/components/camel-spring-xml/src/generated/resources/org/apache/camel/spring/xml/camelContext.json
index fb39212..9a6507f 100644
--- a/components/camel-spring-xml/src/generated/resources/org/apache/camel/spring/xml/camelContext.json
+++ b/components/camel-spring-xml/src/generated/resources/org/apache/camel/spring/xml/camelContext.json
@@ -80,6 +80,7 @@
     "interceptSendToEndpoint": { "kind": "element", "displayName": "Intercept Send To Endpoint", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptSendToEndpointDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Configuration of interceptors that triggers sending messages to endpoints." },
     "restConfiguration": { "kind": "element", "displayName": "Rest Configuration", "required": false, "type": "object", "javaType": "org.apache.camel.model.rest.RestConfigurationDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Configuration for rest-dsl" },
     "rest": { "kind": "element", "displayName": "Rest", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.rest.RestDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the rest services defined using the rest-dsl" },
+    "routeConfiguration": { "kind": "element", "displayName": "Route Configuration", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteConfigurationDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel route configurations" },
     "routeTemplate": { "kind": "element", "displayName": "Route Template", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteTemplateDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel route templates" },
     "route": { "kind": "element", "displayName": "Route", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.RouteDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Contains the Camel routes" },
     "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The id of this node" }
diff --git a/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/CamelContextFactoryBean.java b/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/CamelContextFactoryBean.java
index 87a990e..4aa862d 100644
--- a/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/CamelContextFactoryBean.java
+++ b/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/CamelContextFactoryBean.java
@@ -57,6 +57,7 @@ import org.apache.camel.model.PackageScanDefinition;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RestContextRefDefinition;
 import org.apache.camel.model.RouteBuilderDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteContextRefDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteTemplateContextRefDefinition;
@@ -263,6 +264,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
     private RestConfigurationDefinition restConfiguration;
     @XmlElement(name = "rest")
     private List<RestDefinition> rests = new ArrayList<>();
+    @XmlElement(name = "routeConfiguration")
+    private List<RouteConfigurationDefinition> routeConfigurations = new ArrayList<>();
     @XmlElement(name = "routeTemplate")
     private List<RouteTemplateDefinition> routeTemplates = new ArrayList<>();
     @XmlElement(name = "route")
@@ -557,6 +560,20 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
         this.routes = routes;
     }
 
+    @Override
+    public List<RouteConfigurationDefinition> getRouteConfigurations() {
+        return routeConfigurations;
+    }
+
+    /**
+     * Contains the Camel route configurations
+     */
+    @Override
+    public void setRouteConfigurations(List<RouteConfigurationDefinition> routeConfigurations) {
+        this.routeConfigurations = routeConfigurations;
+    }
+
+    @Override
     public List<RouteTemplateDefinition> getRouteTemplates() {
         return routeTemplates;
     }
@@ -564,6 +581,7 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr
     /**
      * Contains the Camel route templates
      */
+    @Override
     public void setRouteTemplates(List<RouteTemplateDefinition> routeTemplates) {
         this.routeTemplates = routeTemplates;
     }
diff --git a/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/handler/CamelNamespaceHandler.java b/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/handler/CamelNamespaceHandler.java
index d7272be..fed1bba 100644
--- a/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/handler/CamelNamespaceHandler.java
+++ b/components/camel-spring-xml/src/main/java/org/apache/camel/spring/xml/handler/CamelNamespaceHandler.java
@@ -390,6 +390,7 @@ public class CamelNamespaceHandler extends NamespaceHandlerSupport {
                 builder.addPropertyValue("implicitId", implicitId);
                 builder.addPropertyValue("restConfiguration", factoryBean.getRestConfiguration());
                 builder.addPropertyValue("rests", factoryBean.getRests());
+                builder.addPropertyValue("routeConfigurations", factoryBean.getRouteConfigurations());
                 builder.addPropertyValue("routeTemplates", factoryBean.getRouteTemplates());
                 builder.addPropertyValue("routes", factoryBean.getRoutes());
                 builder.addPropertyValue("intercepts", factoryBean.getIntercepts());
diff --git a/components/camel-spring-xml/src/test/java/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.java b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.java
new file mode 100644
index 0000000..5e9a316
--- /dev/null
+++ b/components/camel-spring-xml/src/test/java/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.spring;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class SpringRoutesConfigurationBuilderIdOrPatternTest extends SpringTestSupport {
+
+    @Override
+    protected AbstractXmlApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext(
+                "org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.xml");
+    }
+
+    @Test
+    public void testRoutesConfigurationOnException() throws Exception {
+        getMockEndpoint("mock:error").expectedBodiesReceived("Bye World");
+
+        try {
+            template.sendBody("direct:start", "Hello World");
+            fail("Should throw exception");
+        } catch (Exception e) {
+            // expected
+        }
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.xml b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.xml
new file mode 100644
index 0000000..f8b4d43
--- /dev/null
+++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/SpringRoutesConfigurationBuilderIdOrPatternTest.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+    ">
+
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+
+    <routeConfiguration id="handleError">
+      <onException>
+        <exception>java.lang.Exception</exception>
+        <handled>
+          <constant>true</constant>
+        </handled>
+        <to uri="mock:error"/>
+      </onException>
+    </routeConfiguration>
+
+    <route>
+      <from uri="direct:start"/>
+      <throwException exceptionType="java.lang.IllegalArgumentException" message="Foo"/>
+    </route>
+
+    <route routeConfigurationId="handleError">
+      <from uri="direct:start2"/>
+      <throwException exceptionType="java.lang.IllegalArgumentException" message="Foo2"/>
+    </route>
+
+  </camelContext>
+
+</beans>
diff --git a/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java b/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java
index 0a93950..7e6aaa8 100644
--- a/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java
+++ b/components/camel-test/camel-test-junit5/src/main/java/org/apache/camel/test/junit5/CamelTestSupport.java
@@ -40,6 +40,7 @@ import org.apache.camel.NoSuchEndpointException;
 import org.apache.camel.Predicate;
 import org.apache.camel.Processor;
 import org.apache.camel.ProducerTemplate;
+import org.apache.camel.RouteConfigurationsBuilder;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.Service;
@@ -506,6 +507,13 @@ public abstract class CamelTestSupport
 
         if (isUseRouteBuilder()) {
             RoutesBuilder[] builders = createRouteBuilders();
+            // add configuration before routes
+            for (RoutesBuilder builder : builders) {
+                if (builder instanceof RouteConfigurationsBuilder) {
+                    LOG.debug("Using created route configuration: {}", builder);
+                    context.addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+                }
+            }
             for (RoutesBuilder builder : builders) {
                 LOG.debug("Using created route builder: {}", builder);
                 context.addRoutes(builder);
diff --git a/components/camel-test/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java b/components/camel-test/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
index fd83f71..687d301 100644
--- a/components/camel-test/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
+++ b/components/camel-test/camel-test/src/main/java/org/apache/camel/test/junit4/CamelTestSupport.java
@@ -56,6 +56,7 @@ import org.apache.camel.Predicate;
 import org.apache.camel.Processor;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.Route;
+import org.apache.camel.RouteConfigurationsBuilder;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.Service;
@@ -444,8 +445,15 @@ public abstract class CamelTestSupport extends TestSupport {
 
         if (isUseRouteBuilder()) {
             RoutesBuilder[] builders = createRouteBuilders();
+            // add configuration before routes
             for (RoutesBuilder builder : builders) {
-                LOG.debug("Using created route builder: {}", builder);
+                if (builder instanceof RouteConfigurationsBuilder) {
+                    log.debug("Using created route configuration: {}", builder);
+                    context.addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+                }
+            }
+            for (RoutesBuilder builder : builders) {
+                log.debug("Using created route builder: {}", builder);
                 context.addRoutes(builder);
             }
             replaceFromEndpoints();
diff --git a/components/camel-zookeeper/src/generated/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactoryConfigurer.java b/components/camel-zookeeper/src/generated/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactoryConfigurer.java
index a06cb94..6202e1d 100644
--- a/components/camel-zookeeper/src/generated/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactoryConfigurer.java
+++ b/components/camel-zookeeper/src/generated/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactoryConfigurer.java
@@ -40,7 +40,7 @@ public class ZooKeeperServiceDiscoveryFactoryConfigurer extends org.apache.camel
         case "namespace":
         case "Namespace": target.setNamespace(property(camelContext, java.lang.String.class, value)); return true;
         case "nodes":
-        case "Nodes": target.setNodes(property(camelContext, java.lang.String.class, value)); return true;
+        case "Nodes": target.setNodes(property(camelContext, java.util.List.class, value)); return true;
         case "reconnectbasesleeptime":
         case "ReconnectBaseSleepTime": target.setReconnectBaseSleepTime(property(camelContext, long.class, value)); return true;
         case "reconnectbasesleeptimeunit":
@@ -83,7 +83,7 @@ public class ZooKeeperServiceDiscoveryFactoryConfigurer extends org.apache.camel
         case "namespace":
         case "Namespace": return java.lang.String.class;
         case "nodes":
-        case "Nodes": return java.lang.String.class;
+        case "Nodes": return java.util.List.class;
         case "reconnectbasesleeptime":
         case "ReconnectBaseSleepTime": return long.class;
         case "reconnectbasesleeptimeunit":
@@ -153,6 +153,8 @@ public class ZooKeeperServiceDiscoveryFactoryConfigurer extends org.apache.camel
         switch (ignoreCase ? name.toLowerCase() : name) {
         case "authinfolist":
         case "AuthInfoList": return org.apache.curator.framework.AuthInfo.class;
+        case "nodes":
+        case "Nodes": return java.lang.String.class;
         default: return null;
         }
     }
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index 31843c0..27ac7e9 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -573,6 +573,14 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
     void addRoutes(RoutesBuilder builder) throws Exception;
 
     /**
+     * Adds the routes configurations (global configuration for all routes) from the routes builder.
+     *
+     * @param  builder   the builder which has routes configurations
+     * @throws Exception if the routes configurations could not be created for whatever reason
+     */
+    void addRoutesConfigurations(RouteConfigurationsBuilder builder) throws Exception;
+
+    /**
      * Removes the given route (the route <b>must</b> be stopped before it can be removed).
      * <p/>
      * A route which is removed will be unregistered from JMX, have its services stopped/shutdown and the route
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java b/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java
index ee565ff..4188fa6 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContextAware.java
@@ -25,7 +25,7 @@ public interface CamelContextAware {
      * Set the {@link CamelContext} context if the object is an instance of {@link CamelContextAware}.
      */
     static <T> T trySetCamelContext(T object, CamelContext camelContext) {
-        if (object instanceof CamelContextAware) {
+        if (camelContext != null && object instanceof CamelContextAware) {
             ((CamelContextAware) object).setCamelContext(camelContext);
         }
 
diff --git a/core/camel-api/src/main/java/org/apache/camel/Route.java b/core/camel-api/src/main/java/org/apache/camel/Route.java
index 808dc35..27e5e84 100644
--- a/core/camel-api/src/main/java/org/apache/camel/Route.java
+++ b/core/camel-api/src/main/java/org/apache/camel/Route.java
@@ -44,6 +44,7 @@ public interface Route extends RuntimeConfiguration {
     String REST_PROPERTY = "rest";
     String TEMPLATE_PROPERTY = "template";
     String DESCRIPTION_PROPERTY = "description";
+    String CONFIGURATION_ID_PROPERTY = "configurationId";
 
     /**
      * Gets the route id
@@ -116,6 +117,16 @@ public interface Route extends RuntimeConfiguration {
     String getDescription();
 
     /**
+     * Gets the route configuration id(s) (if any has been configured).
+     * <p/>
+     * The configuration ids is configured using the {@link #CONFIGURATION_ID_PROPERTY} as key in the
+     * {@link #getProperties()}.
+     *
+     * @return the configuration, or <tt>null</tt> if no configuration has been configured.
+     */
+    String getConfigurationId();
+
+    /**
      * Gets the camel context
      *
      * @return the camel context
diff --git a/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java b/core/camel-api/src/main/java/org/apache/camel/RouteConfigurationsBuilder.java
similarity index 64%
copy from core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java
copy to core/camel-api/src/main/java/org/apache/camel/RouteConfigurationsBuilder.java
index d025d67..d9e95d5 100644
--- a/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java
+++ b/core/camel-api/src/main/java/org/apache/camel/RouteConfigurationsBuilder.java
@@ -16,19 +16,17 @@
  */
 package org.apache.camel;
 
-import javax.xml.bind.annotation.XmlEnum;
-
 /**
- * Controls the level of information logged during startup (and shutdown) of {@link CamelContext}.
+ * A route configurations builder is capable of building route configurations using the builder and model classes.
  */
-@XmlEnum
-public enum StartupSummaryLevel {
+public interface RouteConfigurationsBuilder {
 
-    Classic,
-    Verbose,
-    Default,
-    Brief,
-    Oneline,
-    Off
+    /**
+     * Adds the route configurations from this builder to the CamelContext.
+     *
+     * @param  context   the Camel context
+     * @throws Exception is thrown if initialization of route configurations failed
+     */
+    void addRouteConfigurationsToCamelContext(CamelContext context) throws Exception;
 
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java b/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java
index d025d67..8f20f6a 100644
--- a/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java
+++ b/core/camel-api/src/main/java/org/apache/camel/StartupSummaryLevel.java
@@ -24,6 +24,7 @@ import javax.xml.bind.annotation.XmlEnum;
 @XmlEnum
 public enum StartupSummaryLevel {
 
+    @Deprecated
     Classic,
     Verbose,
     Default,
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
index 1c64dff..b75a01e 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/RoutesLoader.java
@@ -20,6 +20,7 @@ import java.util.Arrays;
 import java.util.Collection;
 
 import org.apache.camel.CamelContextAware;
+import org.apache.camel.RouteConfigurationsBuilder;
 import org.apache.camel.RoutesBuilder;
 
 /**
@@ -39,7 +40,14 @@ public interface RoutesLoader extends CamelContextAware {
      * @param resources the resources to be loaded.
      */
     default void loadRoutes(Collection<Resource> resources) throws Exception {
-        for (RoutesBuilder builder : findRoutesBuilders(resources)) {
+        Collection<RoutesBuilder> builders = findRoutesBuilders(resources);
+        // add configuration first before the routes
+        for (RoutesBuilder builder : builders) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                getCamelContext().addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+            }
+        }
+        for (RoutesBuilder builder : builders) {
             getCamelContext().addRoutes(builder);
         }
     }
@@ -51,7 +59,14 @@ public interface RoutesLoader extends CamelContextAware {
      * @param resources the resources to be loaded.
      */
     default void loadRoutes(Resource... resources) throws Exception {
-        for (RoutesBuilder builder : findRoutesBuilders(resources)) {
+        Collection<RoutesBuilder> builders = findRoutesBuilders(resources);
+        // add configuration first before the routes
+        for (RoutesBuilder builder : builders) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                getCamelContext().addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+            }
+        }
+        for (RoutesBuilder builder : builders) {
             getCamelContext().addRoutes(builder);
         }
     }
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 6f9026d..1fbad34 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -64,6 +64,7 @@ import org.apache.camel.ProducerTemplate;
 import org.apache.camel.ResolveEndpointFailedException;
 import org.apache.camel.Route;
 import org.apache.camel.RouteAware;
+import org.apache.camel.RouteConfigurationsBuilder;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.Service;
@@ -1143,7 +1144,12 @@ public abstract class AbstractCamelContext extends BaseService
     }
 
     @Override
-    public void addRoutes(final RoutesBuilder builder) throws Exception {
+    public void addRoutes(RoutesBuilder builder) throws Exception {
+        // in case the builder is also a route configuration builder
+        // then we need to add the configuration first
+        if (builder instanceof RouteConfigurationsBuilder) {
+            addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+        }
         try (LifecycleHelper helper = new LifecycleHelper()) {
             build();
             LOG.debug("Adding routes from builder: {}", builder);
@@ -1151,6 +1157,15 @@ public abstract class AbstractCamelContext extends BaseService
         }
     }
 
+    @Override
+    public void addRoutesConfigurations(RouteConfigurationsBuilder builder) throws Exception {
+        try (LifecycleHelper helper = new LifecycleHelper()) {
+            build();
+            LOG.debug("Adding route configurations from builder: {}", builder);
+            builder.addRouteConfigurationsToCamelContext(AbstractCamelContext.this);
+        }
+    }
+
     public ServiceStatus getRouteStatus(String key) {
         RouteService routeService = routeServices.get(key);
         if (routeService != null) {
@@ -2857,7 +2872,7 @@ public abstract class AbstractCamelContext extends BaseService
             }
         }
 
-        // ant duplicate components in use?
+        // duplicate components in use?
         logDuplicateComponents();
 
         // log startup summary
@@ -2950,6 +2965,7 @@ public abstract class AbstractCamelContext extends BaseService
             int total = 0;
             int disabled = 0;
             List<String> lines = new ArrayList<>();
+            List<String> configs = new ArrayList<>();
             routeStartupOrder.sort(Comparator.comparingInt(RouteStartupOrder::getStartupOrder));
             for (RouteStartupOrder order : routeStartupOrder) {
                 total++;
@@ -2962,6 +2978,11 @@ public abstract class AbstractCamelContext extends BaseService
                 String uri = order.getRoute().getEndpoint().getEndpointBaseUri();
                 uri = URISupport.sanitizeUri(uri);
                 lines.add(String.format("    %s %s (%s)", status, id, uri));
+
+                String cid = order.getRoute().getConfigurationId();
+                if (cid != null) {
+                    configs.add(String.format("    %s (%s)", id, cid));
+                }
             }
             for (Route route : routes) {
                 if (!route.isAutoStartup()) {
@@ -2976,6 +2997,11 @@ public abstract class AbstractCamelContext extends BaseService
                     String uri = route.getEndpoint().getEndpointBaseUri();
                     uri = URISupport.sanitizeUri(uri);
                     lines.add(String.format("    %s %s (%s)", status, id, uri));
+
+                    String cid = route.getConfigurationId();
+                    if (cid != null) {
+                        configs.add(String.format("    %s (%s)", id, cid));
+                    }
                 }
             }
             if (disabled > 0) {
@@ -2988,6 +3014,12 @@ public abstract class AbstractCamelContext extends BaseService
                 for (String line : lines) {
                     LOG.info(line);
                 }
+                if (startupSummaryLevel == StartupSummaryLevel.Verbose) {
+                    LOG.info("Routes configuration summary");
+                    for (String line : configs) {
+                        LOG.info(line);
+                    }
+                }
             }
         }
 
@@ -3006,8 +3038,7 @@ public abstract class AbstractCamelContext extends BaseService
 
     protected void doStartCamel() throws Exception {
         if (!adapt(ExtendedCamelContext.class).getBeanPostProcessor().isEnabled()) {
-            LOG.info(
-                    "BeanPostProcessor is disabled. This means features such as dependency injection of Camel annotations in beans is not supported.");
+            LOG.info("BeanPostProcessor is disabled. Dependency injection of Camel annotations in beans is not supported.");
         }
         if (LOG.isDebugEnabled()) {
             LOG.debug(
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java
index fd877b0..3d39dbf 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultRoute.java
@@ -157,6 +157,12 @@ public class DefaultRoute extends ServiceSupport implements Route {
     }
 
     @Override
+    public String getConfigurationId() {
+        Object value = properties.get(Route.CONFIGURATION_ID_PROPERTY);
+        return value != null ? (String) value : null;
+    }
+
+    @Override
     public void initializeServices() throws Exception {
         // gather all the services for this route
         gatherServices(services);
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultSupervisingRouteController.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultSupervisingRouteController.java
index ece2f9b..158dbe3 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultSupervisingRouteController.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultSupervisingRouteController.java
@@ -481,6 +481,7 @@ public class DefaultSupervisingRouteController extends DefaultRouteController im
         int restarting = 0;
         int exhausted = 0;
         List<String> lines = new ArrayList<>();
+        List<String> configs = new ArrayList<>();
         for (RouteHolder route : routes) {
             String id = route.getId();
             String status = getRouteStatus(id).name();
@@ -491,7 +492,11 @@ public class DefaultSupervisingRouteController extends DefaultRouteController im
                 // use basic endpoint uri to not log verbose details or potential sensitive data
                 String uri = route.get().getEndpoint().getEndpointBaseUri();
                 uri = URISupport.sanitizeUri(uri);
-                lines.add(String.format("\t%s %s (%s)", status, id, uri));
+                lines.add(String.format("    %s %s (%s)", status, id, uri));
+                String cid = route.get().getConfigurationId();
+                if (cid != null) {
+                    configs.add(String.format("    %s (%s)", id, cid));
+                }
             }
         }
         for (RouteHolder route : routeManager.routes.keySet()) {
@@ -503,7 +508,11 @@ public class DefaultSupervisingRouteController extends DefaultRouteController im
             String uri = route.get().getEndpoint().getEndpointBaseUri();
             uri = URISupport.sanitizeUri(uri);
             BackOff backOff = getBackOff(id);
-            lines.add(String.format("\t%s %s (%s) with %s", status, id, uri, backOff));
+            lines.add(String.format("    %s %s (%s) with %s", status, id, uri, backOff));
+            String cid = route.get().getConfigurationId();
+            if (cid != null) {
+                configs.add(String.format("    %s (%s)", id, cid));
+            }
         }
         for (RouteHolder route : routeManager.exhausted.keySet()) {
             total++;
@@ -513,7 +522,11 @@ public class DefaultSupervisingRouteController extends DefaultRouteController im
             // use basic endpoint uri to not log verbose details or potential sensitive data
             String uri = route.get().getEndpoint().getEndpointBaseUri();
             uri = URISupport.sanitizeUri(uri);
-            lines.add(String.format("\t%s %s (%s)", status, id, uri));
+            lines.add(String.format("    %s %s (%s)", status, id, uri));
+            String cid = route.get().getConfigurationId();
+            if (cid != null) {
+                configs.add(String.format("    %s (%s)", id, cid));
+            }
         }
 
         if (restarting == 0 && exhausted == 0) {
@@ -527,6 +540,12 @@ public class DefaultSupervisingRouteController extends DefaultRouteController im
             for (String line : lines) {
                 LOG.info(line);
             }
+            if (getCamelContext().getStartupSummaryLevel() == StartupSummaryLevel.Verbose) {
+                LOG.info("Routes configuration summary");
+                for (String line : configs) {
+                    LOG.info(line);
+                }
+            }
         }
     }
 
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index 8544303..69cd55b 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -54,6 +54,7 @@ import org.apache.camel.model.ModelLifecycleStrategy;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.ProcessorDefinitionHelper;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteDefinitionHelper;
 import org.apache.camel.model.RouteTemplateDefinition;
@@ -287,6 +288,27 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame
     }
 
     @Override
+    public void addRouteConfiguration(RouteConfigurationDefinition routesConfiguration) {
+        if (model == null && isLightweight()) {
+            throw new IllegalStateException("Access to model not supported in lightweight mode");
+        }
+        model.addRouteConfiguration(routesConfiguration);
+    }
+
+    @Override
+    public void addRouteConfigurations(List<RouteConfigurationDefinition> routesConfigurations) {
+        if (model == null && isLightweight()) {
+            throw new IllegalStateException("Access to model not supported in lightweight mode");
+        }
+        model.addRouteConfigurations(routesConfigurations);
+    }
+
+    @Override
+    public List<RouteConfigurationDefinition> getRouteConfigurationDefinitions() {
+        return model.getRouteConfigurationDefinitions();
+    }
+
+    @Override
     public List<RouteDefinition> getRouteDefinitions() {
         if (model == null && isLightweight()) {
             throw new IllegalStateException("Access to model not supported in lightweight mode");
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
index 5802e61..b658b6b 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java
@@ -46,6 +46,7 @@ import org.apache.camel.model.ModelLifecycleStrategy;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.ProcessorDefinitionHelper;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteDefinitionHelper;
 import org.apache.camel.model.RouteFilters;
@@ -79,6 +80,7 @@ public class DefaultModel implements Model {
 
     private ModelReifierFactory modelReifierFactory = new DefaultModelReifierFactory();
     private final List<ModelLifecycleStrategy> modelLifecycleStrategies = new ArrayList<>();
+    private final List<RouteConfigurationDefinition> routesConfigurations = new ArrayList<>();
     private final List<RouteDefinition> routeDefinitions = new ArrayList<>();
     private final List<RouteTemplateDefinition> routeTemplateDefinitions = new ArrayList<>();
     private final List<RestDefinition> restDefinitions = new ArrayList<>();
@@ -114,6 +116,44 @@ public class DefaultModel implements Model {
     }
 
     @Override
+    public void addRouteConfiguration(RouteConfigurationDefinition routesConfiguration) {
+        if (routesConfiguration == null) {
+            return;
+        }
+        // only add if not already exists (route-loader may let Java DSL add route configuration twice
+        // because it extends RouteBuilder as base class)
+        if (!this.routesConfigurations.contains(routesConfiguration)) {
+            // check that there is no id clash
+            if (routesConfiguration.getId() != null) {
+                boolean clash = this.routesConfigurations.stream()
+                        .anyMatch(r -> ObjectHelper.equal(r.getId(), routesConfiguration.getId()));
+                if (clash) {
+                    throw new IllegalArgumentException(
+                            "Route configuration already exists with id: " + routesConfiguration.getId());
+                }
+            }
+            this.routesConfigurations.add(routesConfiguration);
+        }
+    }
+
+    @Override
+    public void addRouteConfigurations(List<RouteConfigurationDefinition> routesConfigurations) {
+        if (routesConfigurations == null || routesConfigurations.isEmpty()) {
+            return;
+        }
+        // only add if not already exists (route-loader may let Java DSL add route configuration twice
+        // because it extends RouteBuilder as base class)
+        for (RouteConfigurationDefinition rc : routesConfigurations) {
+            addRouteConfiguration(rc);
+        }
+    }
+
+    @Override
+    public List<RouteConfigurationDefinition> getRouteConfigurationDefinitions() {
+        return routesConfigurations;
+    }
+
+    @Override
     public synchronized void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
         if (routeDefinitions == null || routeDefinitions.isEmpty()) {
             return;
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
index e56983b..516b4ce 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
@@ -41,6 +41,7 @@ import org.apache.camel.Predicate;
 import org.apache.camel.Processor;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.Route;
+import org.apache.camel.RouteConfigurationsBuilder;
 import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.Service;
@@ -61,6 +62,7 @@ import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.ModelLifecycleStrategy;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteTemplateDefinition;
 import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
@@ -552,6 +554,11 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam
     }
 
     @Override
+    public void addRoutesConfigurations(RouteConfigurationsBuilder builder) throws Exception {
+        delegate.addRoutesConfigurations(builder);
+    }
+
+    @Override
     public boolean removeRoute(String routeId) throws Exception {
         return delegate.removeRoute(routeId);
     }
@@ -1687,6 +1694,21 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam
     }
 
     @Override
+    public void addRouteConfiguration(RouteConfigurationDefinition routesConfiguration) {
+        getModelCamelContext().addRouteConfiguration(routesConfiguration);
+    }
+
+    @Override
+    public void addRouteConfigurations(List<RouteConfigurationDefinition> routesConfigurations) {
+        getModelCamelContext().addRouteConfigurations(routesConfigurations);
+    }
+
+    @Override
+    public List<RouteConfigurationDefinition> getRouteConfigurationDefinitions() {
+        return getModelCamelContext().getRouteConfigurationDefinitions();
+    }
+
+    @Override
     public List<RouteDefinition> getRouteDefinitions() {
         return getModelCamelContext().getRouteDefinitions();
     }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
index fc84451..60db540 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
@@ -49,6 +49,7 @@ import org.apache.camel.Processor;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.ResolveEndpointFailedException;
 import org.apache.camel.Route;
+import org.apache.camel.RouteConfigurationsBuilder;
 import org.apache.camel.RouteTemplateContext;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.RuntimeCamelException;
@@ -1863,6 +1864,11 @@ public class LightweightRuntimeCamelContext implements ExtendedCamelContext, Cat
     }
 
     @Override
+    public void addRoutesConfigurations(RouteConfigurationsBuilder builder) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public boolean removeRoute(String routeId) throws Exception {
         throw new UnsupportedOperationException();
     }
diff --git a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
index 2b03f53..9a05154 100644
--- a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
+++ b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties
@@ -137,6 +137,8 @@ rollback
 roundRobin
 route
 routeBuilder
+routeConfiguration
+routeConfigurations
 routeContextRef
 routeTemplate
 routeTemplateContextRef
@@ -174,7 +176,6 @@ stream-config
 syslog
 tarfile
 templateBean
-templateBeanFactory
 templateParameter
 templateScript
 threadPoolProfile
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index b/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
index c134380..45b5e93 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index
@@ -63,6 +63,8 @@ Resilience4jConfigurationDefinition
 RestContextRefDefinition
 RollbackDefinition
 RouteBuilderDefinition
+RouteConfigurationDefinition
+RouteConfigurationsDefinition
 RouteContextRefDefinition
 RouteDefinition
 RouteTemplateBeanDefinition
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json
new file mode 100644
index 0000000..bdb0150
--- /dev/null
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfiguration.json
@@ -0,0 +1,22 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "routeConfiguration",
+    "title": "Route Configuration",
+    "description": "Reusable configuration for Camel route(s).",
+    "deprecated": false,
+    "label": "configuration",
+    "javaType": "org.apache.camel.model.RouteConfigurationDefinition",
+    "input": false,
+    "output": false
+  },
+  "properties": {
+    "intercept": { "kind": "element", "displayName": "Intercept", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Adds a route for an interceptor that intercepts every processing step." },
+    "interceptFrom": { "kind": "element", "displayName": "Intercept From", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptFromDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Adds a route for an interceptor that intercepts incoming messages on the given endpoint." },
+    "interceptSendToEndpoint": { "kind": "element", "displayName": "Intercept Send To Endpoint", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.InterceptSendToEndpointDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Applies a route for an interceptor if an exchange is send to the given endpoint" },
+    "onException": { "kind": "element", "displayName": "On Exception", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.OnExceptionDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Exception clause for catching certain exceptions and handling them." },
+    "onCompletion": { "kind": "element", "displayName": "On Completion", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.OnCompletionDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "On completion callback for doing custom routing when the org.apache.camel.Exchange is complete." },
+    "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+    "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
+  }
+}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfigurations.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfigurations.json
new file mode 100644
index 0000000..d9d128f
--- /dev/null
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/routeConfigurations.json
@@ -0,0 +1,16 @@
+{
+  "model": {
+    "kind": "model",
+    "name": "routeConfigurations",
+    "title": "Route Configurations",
+    "description": "A series of route configurations",
+    "deprecated": false,
+    "label": "configuration",
+    "javaType": "org.apache.camel.model.RouteConfigurationsDefinition",
+    "input": false,
+    "output": false
+  },
+  "properties": {
+    
+  }
+}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBeanFactory.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBeanFactory.json
deleted file mode 100644
index 538a54b..0000000
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/templateBeanFactory.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "model": {
-    "kind": "model",
-    "name": "templateBeanFactory",
-    "title": "Template Bean Factory",
-    "description": "A route template bean factory (local bean)",
-    "deprecated": false,
-    "label": "configuration",
-    "javaType": "org.apache.camel.model.RouteTemplateBeanFactoryDefinition",
-    "input": false,
-    "output": false
-  },
-  "properties": {
-    "language": { "kind": "attribute", "displayName": "Language", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "bean", "groovy", "joor", "language", "mvel", "ognl" ], "deprecated": false, "autowired": false, "secret": false, "description": "The language to use for creating the bean (such as groovy, joor)" },
-    "script": { "kind": "value", "displayName": "Script", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The script to execute that creates the bean. If the script use the prefix resource: such as resource:classpath:com\/foo\/myscript.groovy, resource:file:\/var\/myscript.groovy, then its loaded from the external resource." }
-  }
-}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/AdviceWith.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/AdviceWith.java
index 81ddafd..b7c23b5 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/AdviceWith.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/AdviceWith.java
@@ -229,6 +229,10 @@ public final class AdviceWith {
         // mixed in correctly as well
         RouteDefinition merged = routes.route(definition);
 
+        // must re-prepare the merged route before it can be used
+        merged.markUnprepared();
+        routes.prepareRoute(merged);
+
         // add the new merged route
         model.getRouteDefinitions().add(0, merged);
 
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
index 2b2bcfc..8aa028e 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
@@ -21,6 +21,7 @@ import java.util.Arrays;
 import java.util.List;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Expression;
 import org.apache.camel.NoSuchEndpointException;
@@ -36,15 +37,15 @@ import org.apache.camel.util.ObjectHelper;
  * Base class for implementation inheritance for different clauses in the
  * <a href="http://camel.apache.org/dsl.html">Java DSL</a>
  */
-public abstract class BuilderSupport {
-    private CamelContext context;
+public abstract class BuilderSupport implements CamelContextAware {
+    private CamelContext camelContext;
     private ErrorHandlerBuilder errorHandlerBuilder;
 
     protected BuilderSupport() {
     }
 
     protected BuilderSupport(CamelContext context) {
-        this.context = context;
+        this.camelContext = context;
     }
 
     // Builder methods
@@ -451,13 +452,33 @@ public abstract class BuilderSupport {
     // Properties
     // -------------------------------------------------------------------------
 
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        if (camelContext != null) {
+            this.camelContext = camelContext;
+        }
+    }
+
+    /**
+     * Get the {@link CamelContext}
+     *
+     * @return camelContext the Camel context
+     */
     public CamelContext getContext() {
-        return context;
+        return getCamelContext();
     }
 
+    /**
+     * @deprecated use {@link #setCamelContext(CamelContext)}
+     */
+    @Deprecated
     public void setContext(CamelContext context) {
-        ObjectHelper.notNull(context, "CamelContext", this);
-        this.context = context;
+        setCamelContext(context);
     }
 
     public boolean hasErrorHandlerBuilder() {
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java
index 48cf43c..55886bc 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java
@@ -24,7 +24,7 @@ import org.apache.camel.util.function.ThrowingConsumer;
  *
  * <pre>
  * RouteBuilder.addRoutes(context, rb ->
- *     rb.from("direct:inbound").bean(ProduceTemplateBean.class)));
+ *     rb.from("direct:inbound").bean(MyBean.class)));
  * </pre>
  *
  * @see RouteBuilder#addRoutes(CamelContext, LambdaRouteBuilder)
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
index 5f9c6db..d5185c8d 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
@@ -36,6 +36,7 @@ import org.apache.camel.model.InterceptSendToEndpointDefinition;
 import org.apache.camel.model.Model;
 import org.apache.camel.model.OnCompletionDefinition;
 import org.apache.camel.model.OnExceptionDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteTemplateDefinition;
 import org.apache.camel.model.RouteTemplatesDefinition;
@@ -85,7 +86,7 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
      *
      * <pre>
      * RouteBuilder.addRoutes(context, rb ->
-     *     rb.from("direct:inbound").bean(ProduceTemplateBean.class)));
+     *     rb.from("direct:inbound").bean(MyBean.class)));
      * </pre>
      *
      * @param  context   the camel context to add routes
@@ -167,6 +168,16 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
     public abstract void configure() throws Exception;
 
     /**
+     * <b>Called on initialization to build routes configuration (global routes configurations) using the fluent builder
+     * syntax.</b>
+     *
+     * @throws Exception can be thrown during configuration
+     */
+    public void configuration() throws Exception {
+        // noop
+    }
+
+    /**
      * Binds the bean to the repository (if possible).
      *
      * @param id   the id of the bean
@@ -462,12 +473,16 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
         configureRoutes(context);
         configureRests(context);
 
-        // but populate rests before routes, as we want to turn rests into
-        // routes
+        // but populate rests before routes, as we want to turn rests into routes
         populateRests();
         populateTransformers();
         populateValidators();
         populateRouteTemplates();
+
+        // ensure routes are prepared before being populated
+        for (RouteDefinition route : routeCollection.getRoutes()) {
+            routeCollection.prepareRoute(route);
+        }
         populateRoutes();
 
         if (this instanceof OnCamelContextEvent) {
@@ -483,7 +498,7 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
      * @throws Exception can be thrown during configuration
      */
     public RoutesDefinition configureRoutes(CamelContext context) throws Exception {
-        setContext(context);
+        setCamelContext(context);
         checkInitialized();
         routeCollection.setCamelContext(context);
         return routeCollection;
@@ -497,7 +512,7 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
      * @throws Exception can be thrown during configuration
      */
     public RestsDefinition configureRests(CamelContext context) throws Exception {
-        setContext(context);
+        setCamelContext(context);
         restCollection.setCamelContext(context);
         return restCollection;
     }
@@ -539,10 +554,10 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
             }
 
             configure();
-            // mark all route definitions as custom prepared because
-            // a route builder prepares the route definitions correctly already
+
             for (RouteDefinition route : getRouteCollection().getRoutes()) {
-                route.markPrepared();
+                // ensure the route is prepared after configure method is complete
+                getRouteCollection().prepareRoute(route);
             }
 
             for (RouteBuilderLifecycleStrategy interceptor : lifecycleInterceptors) {
@@ -673,4 +688,8 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
     protected void configureRouteTemplate(RouteTemplateDefinition routeTemplate) {
         // noop
     }
+
+    protected void configureRouteConfiguration(RouteConfigurationDefinition routesConfiguration) {
+        // noop
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteConfigurationBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteConfigurationBuilder.java
new file mode 100644
index 0000000..a9cb26e
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteConfigurationBuilder.java
@@ -0,0 +1,91 @@
+/*
+ * 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.builder;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RouteConfigurationsBuilder;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.RouteConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationsDefinition;
+
+/**
+ * A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is used for building route configuration(s).
+ */
+public abstract class RouteConfigurationBuilder extends RouteBuilder implements RouteConfigurationsBuilder {
+
+    private final AtomicBoolean initializedConfiguration = new AtomicBoolean();
+    private RouteConfigurationsDefinition routeConfigurationCollection = new RouteConfigurationsDefinition();
+
+    @Override
+    public void configure() throws Exception {
+        // noop
+    }
+
+    public abstract void configuration() throws Exception;
+
+    public RouteConfigurationsDefinition getRouteConfigurationCollection() {
+        return routeConfigurationCollection;
+    }
+
+    public void setRouteConfigurationCollection(RouteConfigurationsDefinition routeConfigurationCollection) {
+        this.routeConfigurationCollection = routeConfigurationCollection;
+    }
+
+    /**
+     * Creates a new route configuration
+     *
+     * @return the builder
+     */
+    public RouteConfigurationDefinition routeConfiguration() {
+        return routeConfiguration(null);
+    }
+
+    /**
+     * Creates a new route configuration
+     *
+     * @return the builder
+     */
+    public RouteConfigurationDefinition routeConfiguration(String id) {
+        getRouteConfigurationCollection().setCamelContext(getCamelContext());
+        RouteConfigurationDefinition answer = getRouteConfigurationCollection().routeConfiguration(id);
+        configureRouteConfiguration(answer);
+        return answer;
+    }
+
+    @Override
+    public void addRouteConfigurationsToCamelContext(CamelContext context) throws Exception {
+        setCamelContext(context);
+        routeConfigurationCollection.setCamelContext(context);
+        if (initializedConfiguration.compareAndSet(false, true)) {
+            configuration();
+        }
+        populateRoutesConfiguration();
+    }
+
+    protected void populateRoutesConfiguration() throws Exception {
+        CamelContext camelContext = getContext();
+        if (camelContext == null) {
+            throw new IllegalArgumentException("CamelContext has not been injected!");
+        }
+        getRouteConfigurationCollection().setCamelContext(camelContext);
+        camelContext.getExtension(Model.class)
+                .addRouteConfigurations(getRouteConfigurationCollection().getRouteConfigurations());
+    }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java b/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java
index 041881b..225965d 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/Model.java
@@ -50,6 +50,27 @@ public interface Model {
     List<ModelLifecycleStrategy> getModelLifecycleStrategies();
 
     /**
+     * Adds a collection of route configuration definitions to the context
+     *
+     * @param routesConfigurations the route configuration(s) definition to add
+     */
+    void addRouteConfigurations(List<RouteConfigurationDefinition> routesConfigurations);
+
+    /**
+     * Adds a single route configuration definition to the context
+     *
+     * @param routesConfiguration the route configuration to add
+     */
+    void addRouteConfiguration(RouteConfigurationDefinition routesConfiguration);
+
+    /**
+     * Returns a list of the current route configuration definitions
+     *
+     * @return list of the current route configuration definitions
+     */
+    List<RouteConfigurationDefinition> getRouteConfigurationDefinitions();
+
+    /**
      * Returns a list of the current route definitions
      *
      * @return list of the current route definitions
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationContainer.java
similarity index 69%
copy from core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java
copy to core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationContainer.java
index ae4e8c8..c46aabe 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationContainer.java
@@ -21,22 +21,22 @@ import java.util.List;
 import javax.xml.bind.annotation.XmlElementRef;
 
 /**
- * Container to hold {@link RouteTemplateDefinition Route}.
+ * Container to hold {@link RouteConfigurationDefinition route configurations}.
  */
-public interface RouteTemplateContainer {
+public interface RouteConfigurationContainer {
 
     /**
-     * Returns the route templates
+     * Returns the route configurations
      *
-     * @return the route templates
+     * @return the route configurations
      */
     @XmlElementRef
-    List<RouteTemplateDefinition> getRouteTemplates();
+    List<RouteConfigurationDefinition> getRouteConfigurations();
 
     /**
-     * Sets the route templates to use
+     * Sets the route configurations to use
      *
-     * @param routes the route templates
+     * @param routes the route configurations
      */
-    void setRouteTemplates(List<RouteTemplateDefinition> routes);
+    void setRouteConfigurations(List<RouteConfigurationDefinition> routes);
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java
new file mode 100644
index 0000000..3a61534
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationDefinition.java
@@ -0,0 +1,198 @@
+/*
+ * 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.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Reusable configuration for Camel route(s).
+ */
+@Metadata(label = "configuration")
+@XmlRootElement(name = "routeConfiguration")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class RouteConfigurationDefinition extends OptionalIdentifiedDefinition<RouteConfigurationDefinition> {
+
+    // TODO: Model for ErrorHandler (requires to move error handler model from spring-xml, blueprint to core)
+
+    @XmlElement(name = "intercept")
+    private List<InterceptDefinition> intercepts = new ArrayList<>();
+    @XmlElement(name = "interceptFrom")
+    private List<InterceptFromDefinition> interceptFroms = new ArrayList<>();
+    @XmlElement(name = "interceptSendToEndpoint")
+    private List<InterceptSendToEndpointDefinition> interceptSendTos = new ArrayList<>();
+    @XmlElement(name = "onException")
+    private List<OnExceptionDefinition> onExceptions = new ArrayList<>();
+    @XmlElement(name = "onCompletion")
+    private List<OnCompletionDefinition> onCompletions = new ArrayList<>();
+
+    public RouteConfigurationDefinition() {
+    }
+
+    @Override
+    public String toString() {
+        return "RoutesConfiguration: " + getId();
+    }
+
+    @Override
+    public String getShortName() {
+        return "routesConfiguration";
+    }
+
+    @Override
+    public String getLabel() {
+        return "RoutesConfiguration " + getId();
+    }
+
+    public List<OnExceptionDefinition> getOnExceptions() {
+        return onExceptions;
+    }
+
+    public void setOnExceptions(List<OnExceptionDefinition> onExceptions) {
+        this.onExceptions = onExceptions;
+    }
+
+    public List<OnCompletionDefinition> getOnCompletions() {
+        return onCompletions;
+    }
+
+    public void setOnCompletions(List<OnCompletionDefinition> onCompletions) {
+        this.onCompletions = onCompletions;
+    }
+
+    public List<InterceptDefinition> getIntercepts() {
+        return intercepts;
+    }
+
+    public void setIntercepts(List<InterceptDefinition> intercepts) {
+        this.intercepts = intercepts;
+    }
+
+    public List<InterceptFromDefinition> getInterceptFroms() {
+        return interceptFroms;
+    }
+
+    public void setInterceptFroms(List<InterceptFromDefinition> interceptFroms) {
+        this.interceptFroms = interceptFroms;
+    }
+
+    public List<InterceptSendToEndpointDefinition> getInterceptSendTos() {
+        return interceptSendTos;
+    }
+
+    public void setInterceptSendTos(List<InterceptSendToEndpointDefinition> interceptSendTos) {
+        this.interceptSendTos = interceptSendTos;
+    }
+
+    // Fluent API
+    // -------------------------------------------------------------------------
+
+    /**
+     * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a> for catching certain exceptions and
+     * handling them.
+     *
+     * @param  exceptionType the exception to catch
+     * @return               the exception builder to configure
+     */
+    public OnExceptionDefinition onException(Class<? extends Throwable> exceptionType) {
+        OnExceptionDefinition answer = new OnExceptionDefinition(exceptionType);
+        onExceptions.add(answer);
+        return answer;
+    }
+
+    /**
+     * <a href="http://camel.apache.org/exception-clause.html">Exception clause</a> for catching certain exceptions and
+     * handling them.
+     *
+     * @param  exceptions list of exceptions to catch
+     * @return            the exception builder to configure
+     */
+    public OnExceptionDefinition onException(Class<? extends Throwable>... exceptions) {
+        OnExceptionDefinition answer = new OnExceptionDefinition(Arrays.asList(exceptions));
+        onExceptions.add(answer);
+        return answer;
+    }
+
+    /**
+     * <a href="http://camel.apache.org/oncompletion.html">On completion</a> callback for doing custom routing when the
+     * {@link org.apache.camel.Exchange} is complete.
+     *
+     * @return the on completion builder to configure
+     */
+    public OnCompletionDefinition onCompletion() {
+        OnCompletionDefinition answer = new OnCompletionDefinition();
+        // is global scoped by default
+        answer.setRouteScoped(false);
+        onCompletions.add(answer);
+        return answer;
+    }
+
+    /**
+     * Adds a route for an interceptor that intercepts every processing step.
+     *
+     * @return the builder
+     */
+    public InterceptDefinition intercept() {
+        InterceptDefinition answer = new InterceptDefinition();
+        intercepts.add(answer);
+        return answer;
+    }
+
+    /**
+     * Adds a route for an interceptor that intercepts incoming messages on any inputs in this route
+     *
+     * @return the builder
+     */
+    public InterceptFromDefinition interceptFrom() {
+        InterceptFromDefinition answer = new InterceptFromDefinition();
+        interceptFroms.add(answer);
+        return answer;
+    }
+
+    /**
+     * Adds a route for an interceptor that intercepts incoming messages on the given endpoint.
+     *
+     * @param  uri endpoint uri
+     * @return     the builder
+     */
+    public InterceptFromDefinition interceptFrom(String uri) {
+        InterceptFromDefinition answer = new InterceptFromDefinition(uri);
+        interceptFroms.add(answer);
+        return answer;
+    }
+
+    /**
+     * Applies a route for an interceptor if an exchange is send to the given endpoint
+     *
+     * @param  uri endpoint uri
+     * @return     the builder
+     */
+    public InterceptSendToEndpointDefinition interceptSendToEndpoint(String uri) {
+        InterceptSendToEndpointDefinition answer = new InterceptSendToEndpointDefinition(uri);
+        interceptSendTos.add(answer);
+        return answer;
+    }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationsDefinition.java
similarity index 51%
copy from core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
copy to core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationsDefinition.java
index 06f272e..92ec02c 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteConfigurationsDefinition.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.model.rest;
+package org.apache.camel.model;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -26,53 +26,35 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.CamelContext;
-import org.apache.camel.model.OptionalIdentifiedDefinition;
 import org.apache.camel.spi.Metadata;
 
 /**
- * A series of rest services defined using the rest-dsl
+ * A series of route configurations
  */
-@Metadata(label = "rest")
-@XmlRootElement(name = "rests")
+@Metadata(label = "configuration")
+@XmlRootElement(name = "routeConfigurations")
 @XmlAccessorType(XmlAccessType.FIELD)
-public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinition> implements RestContainer {
+public class RouteConfigurationsDefinition implements RouteConfigurationContainer {
+
     @XmlElementRef
-    private List<RestDefinition> rests = new ArrayList<>();
+    private List<RouteConfigurationDefinition> routeConfigurations = new ArrayList<>();
     @XmlTransient
     private CamelContext camelContext;
 
-    public RestsDefinition() {
+    public RouteConfigurationsDefinition() {
     }
 
     @Override
     public String toString() {
-        return "Rests: " + rests;
-    }
-
-    @Override
-    public String getShortName() {
-        return "rests";
+        return "RouteConfigurations";
     }
 
-    @Override
-    public String getLabel() {
-        return "Rest " + getId();
+    public List<RouteConfigurationDefinition> getRouteConfigurations() {
+        return routeConfigurations;
     }
 
-    // Properties
-    // -----------------------------------------------------------------------
-
-    @Override
-    public List<RestDefinition> getRests() {
-        return rests;
-    }
-
-    /**
-     * The rest services
-     */
-    @Override
-    public void setRests(List<RestDefinition> rests) {
-        this.rests = rests;
+    public void setRouteConfigurations(List<RouteConfigurationDefinition> routeConfigurations) {
+        this.routeConfigurations = routeConfigurations;
     }
 
     public CamelContext getCamelContext() {
@@ -87,37 +69,46 @@ public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinitio
     // -------------------------------------------------------------------------
 
     /**
-     * Creates a rest DSL
+     * Creates a new route configuration
+     *
+     * @return the builder
      */
-    public RestDefinition rest() {
-        RestDefinition rest = createRest();
-        return rest(rest);
+    public RouteConfigurationDefinition routeConfiguration() {
+        RouteConfigurationDefinition config = createRouteConfiguration(null);
+        getRouteConfigurations().add(config);
+        return config;
     }
 
     /**
-     * Creates a rest DSL
+     * Creates a new route configuration
      *
-     * @param uri the rest path
+     * @return the builder
      */
-    public RestDefinition rest(String uri) {
-        RestDefinition rest = createRest();
-        rest.setPath(uri);
-        return rest(rest);
+    public RouteConfigurationDefinition routeConfiguration(String id) {
+        RouteConfigurationDefinition config = createRouteConfiguration(id);
+        getRouteConfigurations().add(config);
+        return config;
     }
 
     /**
-     * Adds the {@link org.apache.camel.model.rest.RestsDefinition}
+     * Adds the route configuration
+     *
+     * @return the builder
      */
-    public RestDefinition rest(RestDefinition rest) {
-        getRests().add(rest);
-        return rest;
+    public RouteConfigurationDefinition routeConfiguration(RouteConfigurationDefinition config) {
+        getRouteConfigurations().add(config);
+        return config;
     }
 
     // Implementation methods
     // -------------------------------------------------------------------------
-    protected RestDefinition createRest() {
-        RestDefinition rest = new RestDefinition();
-        return rest;
+
+    protected RouteConfigurationDefinition createRouteConfiguration(String id) {
+        RouteConfigurationDefinition config = new RouteConfigurationDefinition();
+        if (id != null) {
+            config.setId(id);
+        }
+        return config;
     }
 
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteContainer.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteContainer.java
index 5e4ba8e..ba548f2 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteContainer.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteContainer.java
@@ -21,7 +21,7 @@ import java.util.List;
 import javax.xml.bind.annotation.XmlElementRef;
 
 /**
- * Container to hold {@link org.apache.camel.model.RouteDefinition Route}.
+ * Container to hold {@link org.apache.camel.model.RouteDefinition routes}.
  */
 public interface RouteContainer {
 
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
index e6a3d0d..40ef2e1 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteDefinition.java
@@ -57,6 +57,7 @@ import org.apache.camel.spi.RoutePolicy;
 public class RouteDefinition extends OutputDefinition<RouteDefinition> implements NamedRoute {
     private final AtomicBoolean prepared = new AtomicBoolean();
     private FromDefinition input;
+    private String routeConfigurationId;
     private String group;
     private String streamCache;
     private String trace;
@@ -203,6 +204,18 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> implement
     }
 
     /**
+     * The route configuration id or pattern this route should use for configuration. Multiple id/pattern can be
+     * separated by comma.
+     *
+     * @param  routeConfigurationId id or pattern
+     * @return                      the builder
+     */
+    public RouteDefinition routeConfigurationId(String routeConfigurationId) {
+        setRouteConfigurationId(routeConfigurationId);
+        return this;
+    }
+
+    /**
      * Set the group name for this route
      *
      * @param  name the group name
@@ -718,6 +731,23 @@ public class RouteDefinition extends OutputDefinition<RouteDefinition> implement
     }
 
     /**
+     * The route configuration id or pattern this route should use for configuration. Multiple id/pattern can be
+     * separated by comma.
+     */
+    public String getRouteConfigurationId() {
+        return routeConfigurationId;
+    }
+
+    /**
+     * The route configuration id or pattern this route should use for configuration. Multiple id/pattern can be
+     * separated by comma.
+     */
+    @XmlAttribute
+    public void setRouteConfigurationId(String routeConfigurationId) {
+        this.routeConfigurationId = routeConfigurationId;
+    }
+
+    /**
      * The group that this route belongs to; could be the name of the RouteBuilder class or be explicitly configured in
      * the XML.
      * <p/>
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java
index ae4e8c8..b2715c8 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplateContainer.java
@@ -21,7 +21,7 @@ import java.util.List;
 import javax.xml.bind.annotation.XmlElementRef;
 
 /**
- * Container to hold {@link RouteTemplateDefinition Route}.
+ * Container to hold {@link RouteTemplateDefinition route templates}.
  */
 public interface RouteTemplateContainer {
 
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java
index c06a722..0beaddd 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RouteTemplatesDefinition.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.ErrorHandlerFactory;
 import org.apache.camel.spi.Metadata;
 
@@ -36,7 +37,7 @@ import org.apache.camel.spi.Metadata;
 @XmlRootElement(name = "routeTemplates")
 @XmlAccessorType(XmlAccessType.FIELD)
 public class RouteTemplatesDefinition extends OptionalIdentifiedDefinition<RouteTemplatesDefinition>
-        implements RouteTemplateContainer {
+        implements RouteTemplateContainer, CamelContextAware {
     @XmlElementRef
     private List<RouteTemplateDefinition> routeTemplates = new ArrayList<>();
     @XmlTransient
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
index b62df39..f978ab4 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/RoutesDefinition.java
@@ -26,11 +26,15 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.Endpoint;
 import org.apache.camel.ErrorHandlerFactory;
 import org.apache.camel.builder.EndpointConsumerBuilder;
 import org.apache.camel.spi.AsEndpointUri;
 import org.apache.camel.spi.Metadata;
+import org.apache.camel.support.PatternHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * A series of Camel routes
@@ -38,7 +42,11 @@ import org.apache.camel.spi.Metadata;
 @Metadata(label = "configuration")
 @XmlRootElement(name = "routes")
 @XmlAccessorType(XmlAccessType.FIELD)
-public class RoutesDefinition extends OptionalIdentifiedDefinition<RoutesDefinition> implements RouteContainer {
+public class RoutesDefinition extends OptionalIdentifiedDefinition<RoutesDefinition>
+        implements RouteContainer, CamelContextAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RoutesDefinition.class);
+
     @XmlElementRef
     private List<RouteDefinition> routes = new ArrayList<>();
     @XmlTransient
@@ -201,15 +209,49 @@ public class RoutesDefinition extends OptionalIdentifiedDefinition<RoutesDefinit
         if (handler != null) {
             route.setErrorHandlerFactoryIfNull(handler);
         }
+        getRoutes().add(route);
+        return route;
+    }
+
+    public void prepareRoute(RouteDefinition route) {
+        if (route.isPrepared()) {
+            return;
+        }
+
+        // merge global and route scoped together
+        List<OnExceptionDefinition> oe = new ArrayList<>(onExceptions);
+        List<InterceptDefinition> icp = new ArrayList<>(intercepts);
+        List<InterceptFromDefinition> ifrom = new ArrayList<>(interceptFroms);
+        List<InterceptSendToEndpointDefinition> ito = new ArrayList<>(interceptSendTos);
+        List<OnCompletionDefinition> oc = new ArrayList<>(onCompletions);
+        if (getCamelContext() != null) {
+            List<RouteConfigurationDefinition> globalConfigurations
+                    = getCamelContext().adapt(ModelCamelContext.class).getRouteConfigurationDefinitions();
+            if (globalConfigurations != null) {
+                globalConfigurations.stream()
+                        // global configurations have no id assigned or is a wildcard
+                        // if the route has a route configuration assigned then use pattern matching
+                        .filter(g -> (g.getId() == null || g.getId().equals("*"))
+                                || (PatternHelper.matchPattern(g.getId(), route.getRouteConfigurationId())))
+                        .forEach(g -> {
+                            oe.addAll(g.getOnExceptions());
+                            icp.addAll(g.getIntercepts());
+                            ifrom.addAll(g.getInterceptFroms());
+                            ito.addAll(g.getInterceptSendTos());
+                            oc.addAll(g.getOnCompletions());
+                        });
+            }
+        }
 
         // must prepare the route before we can add it to the routes list
-        RouteDefinitionHelper.prepareRoute(getCamelContext(), route, getOnExceptions(), getIntercepts(), getInterceptFroms(),
-                getInterceptSendTos(), getOnCompletions());
+        RouteDefinitionHelper.prepareRoute(getCamelContext(), route, oe, icp, ifrom, ito, oc);
+
+        if (LOG.isDebugEnabled() && route.getRouteConfigurationId() != null) {
+            LOG.debug("Route: {} is using routeConfigurationsId: {}", route.getId(), route.getRouteConfigurationId());
+        }
 
-        getRoutes().add(route);
         // mark this route as prepared
         route.markPrepared();
-        return route;
     }
 
     /**
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
index 06f272e..3b8b150 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestsDefinition.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.model.OptionalIdentifiedDefinition;
 import org.apache.camel.spi.Metadata;
 
@@ -35,7 +36,7 @@ import org.apache.camel.spi.Metadata;
 @Metadata(label = "rest")
 @XmlRootElement(name = "rests")
 @XmlAccessorType(XmlAccessType.FIELD)
-public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinition> implements RestContainer {
+public class RestsDefinition extends OptionalIdentifiedDefinition<RestsDefinition> implements RestContainer, CamelContextAware {
     @XmlElementRef
     private List<RestDefinition> rests = new ArrayList<>();
     @XmlTransient
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java
index 10ede58..f921817 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/RouteReifier.java
@@ -58,7 +58,7 @@ public class RouteReifier extends ProcessorReifier<RouteDefinition> {
     private static final String[] RESERVED_PROPERTIES = new String[] {
             Route.ID_PROPERTY, Route.CUSTOM_ID_PROPERTY, Route.PARENT_PROPERTY,
             Route.DESCRIPTION_PROPERTY, Route.GROUP_PROPERTY,
-            Route.REST_PROPERTY };
+            Route.REST_PROPERTY, Route.CONFIGURATION_ID_PROPERTY };
 
     public RouteReifier(CamelContext camelContext, ProcessorDefinition<?> definition) {
         super(camelContext, (RouteDefinition) definition);
@@ -373,6 +373,9 @@ public class RouteReifier extends ProcessorReifier<RouteDefinition> {
         routeProperties.put(Route.REST_PROPERTY, rest);
         String template = Boolean.toString(definition.isTemplate() != null && definition.isTemplate());
         routeProperties.put(Route.TEMPLATE_PROPERTY, template);
+        if (definition.getRouteConfigurationId() != null) {
+            routeProperties.put(Route.CONFIGURATION_ID_PROPERTY, definition.getRouteConfigurationId());
+        }
 
         List<PropertyDefinition> properties = definition.getRouteProperties();
         if (properties != null) {
diff --git a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index 2e88712..9b62c51 100644
--- a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -72,6 +72,8 @@ import org.apache.camel.model.PackageScanDefinition;
 import org.apache.camel.model.Resilience4jConfigurationDefinition;
 import org.apache.camel.model.RestContextRefDefinition;
 import org.apache.camel.model.RouteBuilderDefinition;
+import org.apache.camel.model.RouteConfigurationContainer;
+import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteContainer;
 import org.apache.camel.model.RouteContextRefDefinition;
 import org.apache.camel.model.RouteDefinition;
@@ -132,6 +134,7 @@ import org.apache.camel.spi.UuidGenerator;
 import org.apache.camel.spi.Validator;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.ObjectHelper;
+import org.apache.camel.support.PatternHelper;
 import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.concurrent.ThreadPoolRejectedPolicy;
 import org.slf4j.Logger;
@@ -143,7 +146,7 @@ import org.slf4j.LoggerFactory;
  */
 @XmlAccessorType(XmlAccessType.FIELD)
 public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContext> extends IdentifiedType
-        implements RouteTemplateContainer, RouteContainer, RestContainer {
+        implements RouteTemplateContainer, RouteConfigurationContainer, RouteContainer, RestContainer {
 
     private static final Logger LOG = LoggerFactory.getLogger(AbstractCamelContextFactoryBean.class);
 
@@ -444,6 +447,9 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
             // mark that we are setting up routes
             getContext().adapt(ExtendedCamelContext.class).setupRoutes(false);
 
+            // add route configurations
+            getContext().addRouteConfigurations(getRouteConfigurations());
+
             // init route templates
             initRouteTemplateRefs();
 
@@ -546,9 +552,37 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
             // sanity check first as the route is created using XML
             RouteDefinitionHelper.sanityCheckRoute(route);
 
-            // leverage logic from route definition helper to prepare the route
-            RouteDefinitionHelper.prepareRoute(getContext(), route, getOnExceptions(), getIntercepts(), getInterceptFroms(),
-                    getInterceptSendToEndpoints(), getOnCompletions());
+            // merge global and route scoped together
+            List<OnExceptionDefinition> oe = new ArrayList<>(getOnExceptions());
+            List<InterceptDefinition> icp = new ArrayList<>(getIntercepts());
+            List<InterceptFromDefinition> ifrom = new ArrayList<>(getInterceptFroms());
+            List<InterceptSendToEndpointDefinition> ito = new ArrayList<>(getInterceptSendToEndpoints());
+            List<OnCompletionDefinition> oc = new ArrayList<>(getOnCompletions());
+            if (getContext() != null) {
+                List<RouteConfigurationDefinition> globalConfigurations
+                        = getContext().adapt(ModelCamelContext.class).getRouteConfigurationDefinitions();
+                if (globalConfigurations != null) {
+                    globalConfigurations.stream()
+                            // global configurations have no id assigned or is a wildcard
+                            // if the route has a route configuration assigned then use pattern matching
+                            .filter(g -> (g.getId() == null || g.getId().equals("*"))
+                                    || (PatternHelper.matchPattern(g.getId(), route.getRouteConfigurationId())))
+                            .forEach(g -> {
+                                oe.addAll(g.getOnExceptions());
+                                icp.addAll(g.getIntercepts());
+                                ifrom.addAll(g.getInterceptFroms());
+                                ito.addAll(g.getInterceptSendTos());
+                                oc.addAll(g.getOnCompletions());
+                            });
+                }
+            }
+
+            // must prepare the route before we can add it to the routes list
+            RouteDefinitionHelper.prepareRoute(getContext(), route, oe, icp, ifrom, ito, oc);
+
+            if (LOG.isDebugEnabled() && route.getRouteConfigurationId() != null) {
+                LOG.debug("Route: {} is using routeConfigurationsId: {}", route.getId(), route.getRouteConfigurationId());
+            }
 
             // mark the route as prepared now
             route.markPrepared();
@@ -857,6 +891,9 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
     public abstract List<RouteTemplateDefinition> getRouteTemplates();
 
     @Override
+    public abstract List<RouteConfigurationDefinition> getRouteConfigurations();
+
+    @Override
     public abstract List<RouteDefinition> getRoutes();
 
     @Override
diff --git a/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java b/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
index d3843f8..5b0817c 100644
--- a/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
+++ b/core/camel-core/src/test/java/org/apache/camel/ContextTestSupport.java
@@ -115,9 +115,18 @@ public abstract class ContextTestSupport extends TestSupport {
 
         if (isUseRouteBuilder()) {
             RouteBuilder[] builders = createRouteBuilders();
+            // add configuration before routes
             for (RouteBuilder builder : builders) {
-                log.debug("Using created route builder: {}", builder);
-                context.addRoutes(builder);
+                if (builder instanceof RouteConfigurationsBuilder) {
+                    log.debug("Using created route configuration: {}", builder);
+                    context.addRoutesConfigurations((RouteConfigurationsBuilder) builder);
+                }
+            }
+            for (RouteBuilder builder : builders) {
+                if (!(builder instanceof RouteConfigurationsBuilder)) {
+                    log.debug("Using created route builder: {}", builder);
+                    context.addRoutes(builder);
+                }
             }
         } else {
             log.debug("isUseRouteBuilder() is false");
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderIdOrPatternTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderIdOrPatternTest.java
new file mode 100644
index 0000000..d79b4d0
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderIdOrPatternTest.java
@@ -0,0 +1,243 @@
+/*
+ * 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.model;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.RouteConfigurationsBuilder;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
+import org.apache.camel.support.OrderedComparator;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class RoutesConfigurationBuilderIdOrPatternTest extends ContextTestSupport {
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testRoutesConfigurationOnException() throws Exception {
+        List<RoutesBuilder> routes = new ArrayList<>();
+
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .throwException(new IllegalArgumentException("Foo"));
+            }
+        });
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start2")
+                        .routeConfigurationId("handleError")
+                        .throwException(new IllegalArgumentException("Foo2"));
+            }
+        });
+        routes.add(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // named routes configuration
+                routeConfiguration("handleError").onException(Exception.class).handled(true).to("mock:error");
+            }
+        });
+        context.start();
+
+        // sort routes according to ordered
+        routes.sort(OrderedComparator.get());
+
+        // first add the routes configurations as they are globally for all routes
+        for (RoutesBuilder builder : routes) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+                context.addRoutesConfigurations(rcb);
+            }
+        }
+        // then add the routes
+        for (RoutesBuilder builder : routes) {
+            context.addRoutes(builder);
+        }
+
+        getMockEndpoint("mock:error").expectedBodiesReceived("Bye World");
+
+        try {
+            template.sendBody("direct:start", "Hello World");
+            fail("Should throw exception");
+        } catch (Exception e) {
+            // expected
+        }
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testRoutesConfigurationOnExceptionPattern() throws Exception {
+        List<RoutesBuilder> routes = new ArrayList<>();
+
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .routeConfigurationId("general*")
+                        .throwException(new IllegalArgumentException("Foo"));
+            }
+        });
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start2")
+                        .routeConfigurationId("io*")
+                        .throwException(new IOException("Foo2"));
+            }
+        });
+        routes.add(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // named routes configuration
+                routeConfiguration("generalError").onException(Exception.class).handled(true).to("mock:error");
+                routeConfiguration("ioError").onException(IOException.class).maximumRedeliveries(3).redeliveryDelay(0)
+                        .handled(true).to("mock:io");
+            }
+        });
+        context.start();
+
+        // sort routes according to ordered
+        routes.sort(OrderedComparator.get());
+
+        // first add the routes configurations as they are globally for all routes
+        for (RoutesBuilder builder : routes) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+                context.addRoutesConfigurations(rcb);
+            }
+        }
+        // then add the routes
+        for (RoutesBuilder builder : routes) {
+            context.addRoutes(builder);
+        }
+
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:io").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testRoutesConfigurationOnExceptionDefault() throws Exception {
+        List<RoutesBuilder> routes = new ArrayList<>();
+
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start").routeId("foo")
+                        .throwException(new IllegalArgumentException("Foo"));
+            }
+        });
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start2").routeId("foo2")
+                        .throwException(new IOException("Foo2"));
+            }
+        });
+        routes.add(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // has no name so its the default
+                routeConfiguration().onException(Exception.class).handled(true).to("mock:error");
+                // special for io, but only if included
+                routeConfiguration("ioError").onException(IOException.class).maximumRedeliveries(3).redeliveryDelay(0)
+                        .handled(true).to("mock:io");
+            }
+        });
+        context.start();
+
+        // sort routes according to ordered
+        routes.sort(OrderedComparator.get());
+
+        // first add the routes configurations as they are globally for all routes
+        for (RoutesBuilder builder : routes) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+                context.addRoutesConfigurations(rcb);
+            }
+        }
+        // then add the routes
+        for (RoutesBuilder builder : routes) {
+            context.addRoutes(builder);
+        }
+
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+        getMockEndpoint("mock:io").expectedMessageCount(0);
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+        assertMockEndpointsSatisfied();
+
+        context.removeRoute("foo2");
+
+        // now re-configure route2 to use ioError route configuration
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start2").routeId("foo2")
+                        .routeConfigurationId("ioError")
+                        .throwException(new IOException("Foo2"));
+            }
+        });
+        // try again
+        resetMocks();
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:io").expectedBodiesReceived("Bye World");
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testRoutesConfigurationIdClash() throws Exception {
+        RouteConfigurationBuilder rcb = new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                routeConfiguration().onException(Exception.class).handled(true).to("mock:foo");
+                routeConfiguration("foo").onException(IOException.class).handled(true).to("mock:foo");
+                routeConfiguration("bar").onException(FileNotFoundException.class).handled(true).to("mock:bar");
+                routeConfiguration("foo").onException(IllegalArgumentException.class).handled(true).to("mock:foo");
+            }
+        };
+        try {
+            context.addRoutesConfigurations(rcb);
+            fail("Should throw exception");
+        } catch (IllegalArgumentException e) {
+            assertEquals("Route configuration already exists with id: foo", e.getMessage());
+        }
+    }
+
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderTest.java
new file mode 100644
index 0000000..5e70d18
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationBuilderTest.java
@@ -0,0 +1,310 @@
+/*
+ * 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.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.RouteConfigurationsBuilder;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
+import org.apache.camel.support.OrderedComparator;
+import org.junit.jupiter.api.Test;
+
+public class RoutesConfigurationBuilderTest extends ContextTestSupport {
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testRoutesConfigurationOnException() throws Exception {
+        List<RoutesBuilder> routes = new ArrayList<>();
+
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .throwException(new IllegalArgumentException("Foo"));
+            }
+        });
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start2")
+                        .throwException(new IllegalArgumentException("Foo2"));
+            }
+        });
+        routes.add(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // global routes configuration
+                routeConfiguration().onException(Exception.class).handled(true).to("mock:error");
+            }
+        });
+        context.start();
+
+        // sort routes according to ordered
+        routes.sort(OrderedComparator.get());
+
+        // first add the routes configurations as they are globally for all routes
+        for (RoutesBuilder builder : routes) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+                context.addRoutesConfigurations(rcb);
+            }
+        }
+        // then add the routes
+        for (RoutesBuilder builder : routes) {
+            context.addRoutes(builder);
+        }
+
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testRoutesConfigurationOnCompletion() throws Exception {
+        List<RoutesBuilder> routes = new ArrayList<>();
+
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .to("mock:result");
+            }
+        });
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start2")
+                        // route scoped that overrides the global scoped
+                        .onCompletion().to("mock:done2").end()
+                        .to("mock:result");
+            }
+        });
+        routes.add(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // global routes configuration
+                routeConfiguration().onCompletion().to("mock:done");
+            }
+        });
+        context.start();
+
+        // sort routes according to ordered
+        routes.sort(OrderedComparator.get());
+
+        // first add the routes configurations as they are globally for all routes
+        for (RoutesBuilder builder : routes) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+                context.addRoutesConfigurations(rcb);
+            }
+        }
+        // then add the routes
+        for (RoutesBuilder builder : routes) {
+            context.addRoutes(builder);
+        }
+
+        getMockEndpoint("mock:result").expectedMessageCount(2);
+        getMockEndpoint("mock:done").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:done2").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testRoutesConfigurationIntercept() throws Exception {
+        List<RoutesBuilder> routes = new ArrayList<>();
+
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .setBody(constant("A"))
+                        .setBody(constant("B"))
+                        .to("mock:result");
+            }
+        });
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start2")
+                        .setBody(constant("C"))
+                        .setBody(constant("D"))
+                        .to("mock:result");
+            }
+        });
+        routes.add(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // global routes configuration
+                routeConfiguration().intercept().to("mock:step");
+            }
+        });
+        context.start();
+
+        // sort routes according to ordered
+        routes.sort(OrderedComparator.get());
+
+        // first add the routes configurations as they are globally for all routes
+        for (RoutesBuilder builder : routes) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+                context.addRoutesConfigurations(rcb);
+            }
+        }
+        // then add the routes
+        for (RoutesBuilder builder : routes) {
+            context.addRoutes(builder);
+        }
+
+        getMockEndpoint("mock:result").expectedMessageCount(2);
+        getMockEndpoint("mock:step").expectedBodiesReceived("Hello World", "A", "B", "Bye World", "C", "D");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testRoutesConfigurationInterceptFrom() throws Exception {
+        List<RoutesBuilder> routes = new ArrayList<>();
+
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("seda:start")
+                        .setBody(constant("A"))
+                        .setBody(constant("B"))
+                        .to("mock:result");
+            }
+        });
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start2")
+                        .setBody(constant("C"))
+                        .setBody(constant("D"))
+                        .to("mock:result");
+            }
+        });
+        routes.add(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // global routes configuration
+                routeConfiguration().interceptFrom("direct*").to("mock:step");
+            }
+        });
+        context.start();
+
+        // sort routes according to ordered
+        routes.sort(OrderedComparator.get());
+
+        // first add the routes configurations as they are globally for all routes
+        for (RoutesBuilder builder : routes) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+                context.addRoutesConfigurations(rcb);
+            }
+        }
+        // then add the routes
+        for (RoutesBuilder builder : routes) {
+            context.addRoutes(builder);
+        }
+
+        getMockEndpoint("mock:result").expectedMessageCount(2);
+        getMockEndpoint("mock:step").expectedBodiesReceived("Bye World");
+
+        template.sendBody("seda:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testRoutesConfigurationInterceptSendTo() throws Exception {
+        List<RoutesBuilder> routes = new ArrayList<>();
+
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .setBody(constant("A"))
+                        .to("mock:foo")
+                        .setBody(constant("B"))
+                        .to("mock:bar")
+                        .to("mock:result");
+            }
+        });
+        routes.add(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start2")
+                        .setBody(constant("C"))
+                        .to("mock:foo")
+                        .setBody(constant("D"))
+                        .to("mock:bar")
+                        .to("mock:result");
+            }
+        });
+        routes.add(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // global routes configuration
+                routeConfiguration().interceptSendToEndpoint("mock:foo").to("mock:step");
+            }
+        });
+        context.start();
+
+        // sort routes according to ordered
+        routes.sort(OrderedComparator.get());
+
+        // first add the routes configurations as they are globally for all routes
+        for (RoutesBuilder builder : routes) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+                context.addRoutesConfigurations(rcb);
+            }
+        }
+        // then add the routes
+        for (RoutesBuilder builder : routes) {
+            context.addRoutes(builder);
+        }
+
+        getMockEndpoint("mock:result").expectedMessageCount(2);
+        getMockEndpoint("mock:step").expectedBodiesReceived("A", "C");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationMultipleRouteBuilderTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationMultipleRouteBuilderTest.java
new file mode 100644
index 0000000..d4fe65a
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationMultipleRouteBuilderTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.model;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
+import org.junit.jupiter.api.Test;
+
+public class RoutesConfigurationMultipleRouteBuilderTest extends ContextTestSupport {
+
+    @Override
+    public boolean isUseRouteBuilder() {
+        return false;
+    }
+
+    @Test
+    public void testRoutesConfiguration() throws Exception {
+        context.addRoutesConfigurations(new RouteConfigurationBuilder() {
+            @Override
+            public void configuration() throws Exception {
+                // global configuration for all routes
+                routeConfiguration().onException(Exception.class).handled(true).to("mock:error");
+            }
+        });
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                        .throwException(new IllegalArgumentException("Foo"));
+            }
+        });
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start2")
+                        .throwException(new IllegalArgumentException("Foo2"));
+            }
+        });
+
+        context.start();
+
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationTest.java b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationTest.java
new file mode 100644
index 0000000..a737fc1
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/model/RoutesConfigurationTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.model;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
+import org.junit.jupiter.api.Test;
+
+public class RoutesConfigurationTest extends ContextTestSupport {
+
+    @Test
+    public void testRoutesConfiguration() throws Exception {
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder[] createRouteBuilders() throws Exception {
+        return new RouteBuilder[] {
+                new RouteBuilder() {
+                    @Override
+                    public void configure() throws Exception {
+                        from("direct:start")
+                                .throwException(new IllegalArgumentException("Foo"));
+
+                        from("direct:start2")
+                                .throwException(new IllegalArgumentException("Foo2"));
+                    }
+                },
+                new RouteConfigurationBuilder() {
+                    @Override
+                    public void configuration() throws Exception {
+                        // global routes configuration
+                        routeConfiguration().onException(Exception.class).handled(true).to("mock:error");
+                    }
+                }
+        };
+    }
+
+}
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteBuilder.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteBuilder.java
index f9e9190..77ad7fc 100644
--- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteBuilder.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteBuilder.java
@@ -41,15 +41,15 @@ public abstract class EndpointRouteBuilder extends RouteBuilder implements Endpo
      * Add routes to a context using a lambda expression. It can be used as following:
      *
      * <pre>
-     * RouteBuilder.addRoutes(context, rb -&gt;
-     *     rb.from("direct:inbound").bean(ProduceTemplateBean.class)));
+     * EndpointRouteBuilder.addEndpointRoutes(context, rb -&gt;
+     *     rb.from(rb.direct("inbound")).bean(MyBean.class)));
      * </pre>
      *
      * @param  context   the camel context to add routes
      * @param  rbc       a lambda expression receiving the {@code RouteBuilder} to use for creating routes
      * @throws Exception if an error occurs
      */
-    public static void addEndpointRoutes(CamelContext context, ThrowingConsumer<EndpointRouteBuilder, Exception> rbc)
+    public static void addEndpointRoutes(CamelContext context, LambdaEndpointRouteBuilder rbc)
             throws Exception {
         context.addRoutes(new EndpointRouteBuilder(context) {
             @Override
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteConfigurationBuilder.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteConfigurationBuilder.java
new file mode 100644
index 0000000..7122067
--- /dev/null
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/EndpointRouteConfigurationBuilder.java
@@ -0,0 +1,91 @@
+/*
+ * 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.builder.endpoint;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RouteConfigurationsBuilder;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.RouteConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationsDefinition;
+
+/**
+ * A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is used for building route configuration(s).
+ */
+public abstract class EndpointRouteConfigurationBuilder extends EndpointRouteBuilder implements RouteConfigurationsBuilder {
+
+    private final AtomicBoolean initializedConfiguration = new AtomicBoolean();
+    private RouteConfigurationsDefinition routeConfigurationCollection = new RouteConfigurationsDefinition();
+
+    @Override
+    public void configure() throws Exception {
+        // noop
+    }
+
+    public abstract void configuration() throws Exception;
+
+    public RouteConfigurationsDefinition getRouteConfigurationCollection() {
+        return routeConfigurationCollection;
+    }
+
+    public void setRouteConfigurationCollection(RouteConfigurationsDefinition routeConfigurationCollection) {
+        this.routeConfigurationCollection = routeConfigurationCollection;
+    }
+
+    /**
+     * Creates a new route configuration
+     *
+     * @return the builder
+     */
+    public RouteConfigurationDefinition routeConfiguration() {
+        return routeConfiguration(null);
+    }
+
+    /**
+     * Creates a new route configuration
+     *
+     * @return the builder
+     */
+    public RouteConfigurationDefinition routeConfiguration(String id) {
+        getRouteConfigurationCollection().setCamelContext(getCamelContext());
+        RouteConfigurationDefinition answer = getRouteConfigurationCollection().routeConfiguration(id);
+        configureRouteConfiguration(answer);
+        return answer;
+    }
+
+    @Override
+    public void addRouteConfigurationsToCamelContext(CamelContext context) throws Exception {
+        setCamelContext(context);
+        routeConfigurationCollection.setCamelContext(context);
+        if (initializedConfiguration.compareAndSet(false, true)) {
+            configuration();
+        }
+        populateRoutesConfiguration();
+    }
+
+    protected void populateRoutesConfiguration() throws Exception {
+        CamelContext camelContext = getContext();
+        if (camelContext == null) {
+            throw new IllegalArgumentException("CamelContext has not been injected!");
+        }
+        getRouteConfigurationCollection().setCamelContext(camelContext);
+        camelContext.getExtension(Model.class)
+                .addRouteConfigurations(getRouteConfigurationCollection().getRouteConfigurations());
+    }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilder.java
similarity index 75%
copy from core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java
copy to core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilder.java
index 48cf43c..d03121c 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/LambdaRouteBuilder.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilder.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.builder;
+package org.apache.camel.builder.endpoint;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.util.function.ThrowingConsumer;
@@ -23,13 +23,13 @@ import org.apache.camel.util.function.ThrowingConsumer;
  * Functional interface for adding routes to a context using a lambda expression. It can be used as following:
  *
  * <pre>
- * RouteBuilder.addRoutes(context, rb ->
- *     rb.from("direct:inbound").bean(ProduceTemplateBean.class)));
+ * EndpointRouteBuilder.addEndpointRoutes(context, rb ->
+ *     rb.from(rb.direct("inbound")).bean(MyBean.class)));
  * </pre>
  *
- * @see RouteBuilder#addRoutes(CamelContext, LambdaRouteBuilder)
+ * @see EndpointRouteBuilder#addEndpointRoutes(CamelContext, LambdaEndpointRouteBuilder)
  */
 @FunctionalInterface
-public interface LambdaRouteBuilder extends ThrowingConsumer<RouteBuilder, Exception> {
+public interface LambdaEndpointRouteBuilder extends ThrowingConsumer<EndpointRouteBuilder, Exception> {
 
 }
diff --git a/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/EndpointRoutesConfigurationTest.java b/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/EndpointRoutesConfigurationTest.java
new file mode 100644
index 0000000..a67e5a7
--- /dev/null
+++ b/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/EndpointRoutesConfigurationTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.builder.endpoint;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+public class EndpointRoutesConfigurationTest extends BaseEndpointDslTest {
+
+    @Test
+    public void testEndpointRoutesConfiguration() throws Exception {
+        getMockEndpoint("mock:error").expectedBodiesReceived("Hello World", "Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+        template.sendBody("direct:start2", "Bye World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder[] createRouteBuilders() throws Exception {
+        return new RouteBuilder[] {
+                new EndpointRouteBuilder() {
+                    @Override
+                    public void configure() throws Exception {
+                        from(direct("start"))
+                                .throwException(new IllegalArgumentException("Foo"));
+
+                        from(direct("start2"))
+                                .throwException(new IllegalArgumentException("Foo2"));
+                    }
+                },
+                new EndpointRouteConfigurationBuilder() {
+                    @Override
+                    public void configuration() throws Exception {
+                        // global routes configuration
+                        routeConfiguration().onException(Exception.class).handled(true).to(mock("error"));
+                    }
+                }
+        };
+    }
+
+}
diff --git a/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilderTest.java b/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilderTest.java
new file mode 100644
index 0000000..fad48ee
--- /dev/null
+++ b/core/camel-endpointdsl/src/test/java/org/apache/camel/builder/endpoint/LambdaEndpointRouteBuilderTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.builder.endpoint;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class LambdaEndpointRouteBuilderTest extends BaseEndpointDslTest {
+
+    @Test
+    public void testLambda() throws Exception {
+        assertEquals(0, context.getRoutesSize());
+
+        LambdaEndpointRouteBuilder builder = rb -> rb.from(rb.direct("start")).to(rb.mock("result"));
+        context.addRoutes(new EndpointRouteBuilder(context) {
+            @Override
+            public void configure() throws Exception {
+                builder.accept(this);
+            }
+        });
+        context.start();
+
+        assertEquals(1, context.getRoutesSize());
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("Hello World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testLambdaTwo() throws Exception {
+        assertEquals(0, context.getRoutesSize());
+
+        EndpointRouteBuilder.addEndpointRoutes(context, rb -> rb.from(rb.direct("start")).to(rb.mock("result")));
+
+        context.start();
+
+        assertEquals(1, context.getRoutesSize());
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("Hello World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testLambdaSimple() throws Exception {
+        assertEquals(0, context.getRoutesSize());
+
+        EndpointRouteBuilder.addEndpointRoutes(context,
+                rb -> rb.from(rb.direct("start")).transform(rb.simple("Hello ${body}")).to(rb.mock("result")));
+
+        context.start();
+
+        assertEquals(1, context.getRoutesSize());
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived("Hello World");
+
+        template.sendBody("direct:start", "World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+}
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java b/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java
index 4440dfb..1a543b1 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java
@@ -23,6 +23,7 @@ import java.util.Set;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.RouteConfigurationsBuilder;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.CamelBeanPostProcessor;
@@ -143,7 +144,6 @@ public class RoutesConfigurer {
 
                 // lets use Camel's injector so the class has some support for dependency injection
                 RoutesBuilder builder = camelContext.getInjector().newInstance(routeClazz);
-
                 routes.add(builder);
             }
         }
@@ -153,7 +153,6 @@ public class RoutesConfigurer {
             Set<Class<?>> set = camelContext.adapt(ExtendedCamelContext.class)
                     .getPackageScanClassResolver()
                     .findImplementations(RoutesBuilder.class, pkgs);
-
             for (Class<?> routeClazz : set) {
                 Object builder = camelContext.getInjector().newInstance(routeClazz);
                 if (builder instanceof RoutesBuilder) {
@@ -175,6 +174,11 @@ public class RoutesConfigurer {
                         getJavaRoutesIncludePattern());
                 routes.addAll(routesFromRegistry);
 
+                if (LOG.isDebugEnabled() && !routesFromRegistry.isEmpty()) {
+                    LOG.debug("Discovered {} additional RoutesBuilder from registry: {}", routesFromRegistry.size(),
+                            getRoutesIncludePattern());
+                }
+
                 // add discovered routes from directories
                 StopWatch watch = new StopWatch();
                 Collection<RoutesBuilder> routesFromDirectory = getRoutesCollector().collectRoutesFromDirectory(
@@ -183,8 +187,8 @@ public class RoutesConfigurer {
                         getRoutesIncludePattern());
                 routes.addAll(routesFromDirectory);
 
-                if (!routesFromDirectory.isEmpty()) {
-                    LOG.info("Loaded {} additional RoutesBuilder from: {} (took {})", routesFromDirectory.size(),
+                if (LOG.isDebugEnabled() && !routesFromDirectory.isEmpty()) {
+                    LOG.debug("Loaded {} additional RoutesBuilder from: {} (took {})", routesFromDirectory.size(),
                             getRoutesIncludePattern(), TimeUtils.printDuration(watch.taken()));
                 }
             } catch (Exception e) {
@@ -195,26 +199,39 @@ public class RoutesConfigurer {
         if (getBeanPostProcessor() != null) {
             // lets use Camel's bean post processor on any existing route builder classes
             // so the instance has some support for dependency injection
-
             for (RoutesBuilder routeBuilder : routes) {
                 getBeanPostProcessor().postProcessBeforeInitialization(routeBuilder, routeBuilder.getClass().getName());
                 getBeanPostProcessor().postProcessAfterInitialization(routeBuilder, routeBuilder.getClass().getName());
             }
         }
 
+        // add the discovered routes
+        addDiscoveredRoutes(camelContext, routes);
+
+        // then discover and add templates
+        Set<ConfigureRouteTemplates> set = camelContext.getRegistry().findByType(ConfigureRouteTemplates.class);
+        for (ConfigureRouteTemplates crt : set) {
+            LOG.debug("Configuring route templates via: {}", crt);
+            crt.configure(camelContext);
+        }
+    }
+
+    private void addDiscoveredRoutes(CamelContext camelContext, List<RoutesBuilder> routes) throws Exception {
         // sort routes according to ordered
         routes.sort(OrderedComparator.get());
 
+        // first add the routes configurations as they are globally for all routes
+        for (RoutesBuilder builder : routes) {
+            if (builder instanceof RouteConfigurationsBuilder) {
+                RouteConfigurationsBuilder rcb = (RouteConfigurationsBuilder) builder;
+                LOG.debug("Adding routes configurations into CamelContext from RouteConfigurationsBuilder: {}", rcb);
+                camelContext.addRoutesConfigurations(rcb);
+            }
+        }
         // then add the routes
         for (RoutesBuilder builder : routes) {
             LOG.debug("Adding routes into CamelContext from RoutesBuilder: {}", builder);
             camelContext.addRoutes(builder);
         }
-
-        Set<ConfigureRouteTemplates> set = camelContext.getRegistry().findByType(ConfigureRouteTemplates.class);
-        for (ConfigureRouteTemplates crt : set) {
-            LOG.debug("Configuring route templates via: {}", crt);
-            crt.configure(camelContext);
-        }
     }
 }
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java
index 304998a..e019e88 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedRouteMBean.java
@@ -35,6 +35,9 @@ public interface ManagedRouteMBean extends ManagedPerformanceCounterMBean {
     @ManagedAttribute(description = "Route Description")
     String getDescription();
 
+    @ManagedAttribute(description = "Route Configuration ID")
+    String getRouteConfigurationId();
+
     @ManagedAttribute(description = "Route Endpoint URI", mask = true)
     String getEndpointUri();
 
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java
index 87ab081..988dc20 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedRoute.java
@@ -71,6 +71,7 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList
 
     protected final Route route;
     protected final String description;
+    protected final String configurationId;
     protected final CamelContext context;
     private final LoadTriplet load = new LoadTriplet();
     private final String jmxDomain;
@@ -79,6 +80,7 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList
         this.route = route;
         this.context = context;
         this.description = route.getDescription();
+        this.configurationId = route.getConfigurationId();
         this.jmxDomain = context.getManagementStrategy().getManagementAgent().getMBeanObjectDomainName();
     }
 
@@ -143,6 +145,11 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList
     }
 
     @Override
+    public String getRouteConfigurationId() {
+        return configurationId;
+    }
+
+    @Override
     public String getEndpointUri() {
         if (route.getEndpoint() != null) {
             return route.getEndpoint().getEndpointUri();
@@ -171,10 +178,6 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList
         return route.getUptimeMillis();
     }
 
-    public Integer getInflightExchanges() {
-        return (int) super.getExchangesInflight();
-    }
-
     @Override
     public String getCamelId() {
         return context.getName();
@@ -646,6 +649,10 @@ public class ManagedRoute extends ManagedPerformanceCounter implements TimerList
         }
     }
 
+    private Integer getInflightExchanges() {
+        return (int) super.getExchangesInflight();
+    }
+
     /**
      * Used for sorting the processor mbeans accordingly to their index.
      */
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index d444e5e..b33981d 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -936,6 +936,53 @@ public class ModelParser extends BaseParser {
             return identifiedTypeAttributeHandler().accept(def, key, val);
         }, noElementHandler(), noValueHandler());
     }
+    protected RouteConfigurationDefinition doParseRouteConfigurationDefinition() throws IOException, XmlPullParserException {
+        return doParse(new RouteConfigurationDefinition(),
+            optionalIdentifiedDefinitionAttributeHandler(), (def, key) -> {
+            switch (key) {
+                case "interceptFrom": doAdd(doParseInterceptFromDefinition(), def.getInterceptFroms(), def::setInterceptFroms); break;
+                case "interceptSendToEndpoint": doAdd(doParseInterceptSendToEndpointDefinition(), def.getInterceptSendTos(), def::setInterceptSendTos); break;
+                case "intercept": doAdd(doParseInterceptDefinition(), def.getIntercepts(), def::setIntercepts); break;
+                case "onCompletion": doAdd(doParseOnCompletionDefinition(), def.getOnCompletions(), def::setOnCompletions); break;
+                case "onException": doAdd(doParseOnExceptionDefinition(), def.getOnExceptions(), def::setOnExceptions); break;
+                default: return optionalIdentifiedDefinitionElementHandler().accept(def, key);
+            }
+            return true;
+        }, noValueHandler());
+    }
+    public Optional<RouteConfigurationsDefinition> parseRouteConfigurationsDefinition()
+            throws IOException, XmlPullParserException {
+        String tag = getNextTag("routeConfigurations", "routeConfiguration");
+        if (tag != null) {
+            switch (tag) {
+                case "routeConfigurations" : return Optional.of(doParseRouteConfigurationsDefinition());
+                case "routeConfiguration" : return parseSingleRouteConfigurationsDefinition();
+            }
+        }
+        return Optional.empty();
+    }
+    private Optional<RouteConfigurationsDefinition> parseSingleRouteConfigurationsDefinition()
+            throws IOException, XmlPullParserException {
+        Optional<RouteConfigurationDefinition> single = Optional.of(doParseRouteConfigurationDefinition());
+        if (single.isPresent()) {
+            List<RouteConfigurationDefinition> list = new ArrayList<>();
+            list.add(single.get());
+            RouteConfigurationsDefinition def = new RouteConfigurationsDefinition();
+            def.setRouteConfigurations(list);
+            return Optional.of(def);
+        }
+        return Optional.empty();
+    }
+    protected RouteConfigurationsDefinition doParseRouteConfigurationsDefinition() throws IOException, XmlPullParserException {
+        return doParse(new RouteConfigurationsDefinition(),
+            noAttributeHandler(), (def, key) -> {
+            if ("routeConfiguration".equals(key)) {
+                doAdd(doParseRouteConfigurationDefinition(), def.getRouteConfigurations(), def::setRouteConfigurations);
+                return true;
+            }
+            return false;
+        }, noValueHandler());
+    }
     protected RouteContextRefDefinition doParseRouteContextRefDefinition() throws IOException, XmlPullParserException {
         return doParse(new RouteContextRefDefinition(), (def, key, val) -> {
             if ("ref".equals(key)) {
@@ -954,6 +1001,7 @@ public class ModelParser extends BaseParser {
                 case "group": def.setGroup(val); break;
                 case "logMask": def.setLogMask(val); break;
                 case "messageHistory": def.setMessageHistory(val); break;
+                case "routeConfigurationId": def.setRouteConfigurationId(val); break;
                 case "routePolicyRef": def.setRoutePolicyRef(val); break;
                 case "shutdownRoute": def.setShutdownRoute(val); break;
                 case "shutdownRunningTask": def.setShutdownRunningTask(val); break;
diff --git a/docs/user-manual/modules/ROOT/nav.adoc b/docs/user-manual/modules/ROOT/nav.adoc
index 4facacc..e877c00 100644
--- a/docs/user-manual/modules/ROOT/nav.adoc
+++ b/docs/user-manual/modules/ROOT/nav.adoc
@@ -82,6 +82,7 @@
 ** xref:lambda-route-builder.adoc[LambdaRouteBuilder]
 ** xref:route-controller.adoc[RouteController]
 ** xref:route-policy.adoc[RoutePolicy]
+** xref:route-configuration.adoc[RouteConfiguration]
 ** xref:route-template.adoc[RouteTemplate]
 ** xref:routes.adoc[Routes]
 ** xref:stream-caching.adoc[Stream caching]
diff --git a/docs/user-manual/modules/ROOT/pages/index.adoc b/docs/user-manual/modules/ROOT/pages/index.adoc
index 86bce1c..36a57b0 100644
--- a/docs/user-manual/modules/ROOT/pages/index.adoc
+++ b/docs/user-manual/modules/ROOT/pages/index.adoc
@@ -117,6 +117,7 @@ camel routes without them knowing
 * xref:lambda-route-builder.adoc[LambdaRouteBuilder]
 * xref:route-controller.adoc[RouteController]
 * xref:route-policy.adoc[RoutePolicy]
+* xref:route-configuration.adoc[RouteConfiguration]
 * xref:route-template.adoc[RouteTemplate]
 * xref:routes.adoc[Routes]
 * xref:stream-caching.adoc[Stream caching]
diff --git a/docs/user-manual/modules/ROOT/pages/route-configuration.adoc b/docs/user-manual/modules/ROOT/pages/route-configuration.adoc
new file mode 100644
index 0000000..f0c5acb
--- /dev/null
+++ b/docs/user-manual/modules/ROOT/pages/route-configuration.adoc
@@ -0,0 +1,294 @@
+[[RouteConfiguration]]
+= Route Configuration
+
+Camel 3.12 introduces route configuration which is used for separating configurations
+from the routes. This can be used in situations such as configuring different error handling across a set of routes.
+In previous versions of Camel this was more cumbersome to do, as you would either have
+to copy the same configuration to a set of routes or rely on global error handling configuration.
+
+Now you can configure a number of route configurations, and then specify on each route
+which configuration to use (you can use match by ids, wildcards, and regular expression).
+
+The route configuration is supported by all DSL's, so useable by: Java, XML, Groovy, XML, Kotlin and so forth.
+
+In the route configuration you can setup common strategies for:
+
+- error handling via `onException`
+- interceptors via `intercept`, `interceptFrom`, `interceptSendTo`
+- on completions via `onCompletion`
+
+
+== Route Configuration Builder in Java DSL
+
+With Java DSL you can use `RouteConfigurationBuilder` to specify the configuration as shown below.
+The builder is similar to `RouteBuilder` so its familiar how to use.
+
+[source,java]
+----
+public class MyJavaErrorHandler extends RouteConfigurationBuilder {
+
+    @Override
+    public void configuration() throws Exception {
+        routeConfiguration("javaError")
+            .onException(Exception.class).handled(true)
+            .log("Java WARN: ${exception.message}");
+    }
+}
+----
+
+NOTE: The `RouteConfigurationBuilder` uses `configuration` as the method where the configuration is coded.
+This is on purpose to not use the `configure` method which the regular Java DSL `RouteBuilder`
+uses for coding Camel routes.
+
+In the example above, then there is only one route configuration which has been assigned the ID _javaError_.
+This ID allows us to refer to this configuration later when you want to assign which routes are using the configuration.
+
+This configuration is a basic configuration that just catches and handles all exceptions and logs a WARN message.
+
+=== Assigning route configurations to routes
+
+To use this configuration in your routes, then you can assign it with `routeConfigurationId` as shown:
+
+[source,java]
+----
+public class MyJavaRouteBuilder extends RouteBuilder {
+
+    @Override
+    public void configure() throws Exception {
+        from("timer:java?period=2s")
+            // refer to the route configuration by the id to use for this route
+            .routeConfigurationId("javaError")
+            .setBody(method(MyJavaRouteBuilder.class, "randomNumber"))
+            .log("Random number ${body}")
+            .filter(simple("${body} < 30"))
+                .throwException(new IllegalArgumentException("The number is too low"));
+    }
+
+    public static int randomNumber() {
+        return new Random().nextInt(100);
+    }
+}
+----
+
+In the `routeConfigurationId` the configuration to use is specified by the ID, eg _javaError_.
+
+Multiple configurations can be assigned (separated by comma), such as:
+
+[source,java]
+----
+.routeConfigurationId("javaError,myAudit")
+----
+
+The route configurations supports matching by:
+
+- match by exact ID name. This is the sample we have seen above.
+- match by wildcard
+- match by regular expression.
+
+Wildcards is match that the text before the * is matched against the given configuration and if it also starts with the same characters its a match. For instance you can do:
+
+[source,java]
+----
+.routeConfigurationId("java*,myAudit")
+----
+
+Here we use wildcard in _java*_ which means any configuration that starts with java is a match.
+
+Match by regular expression is just like match by wildcard but using regex instead.
+
+[source,java]
+----
+.routeConfigurationId(".*error.*")
+----
+
+Here we want to match any routes that has _error_ in the name.
+
+=== Adding route configurations to CamelContext
+
+Because a `RouteConfigurationBuilder` is also a `RouteBuilder` then you add route configurations
+the same way for `RouteBuilder` such as using the API on `CamelContext`
+
+[source,java]
+----
+CamelContext context = ...
+// add the route configuration
+context.addRoutes(new MyJavaErrorHandler());
+// add the regular route
+context.addRoutes(new MyJavaRouteBuilder());
+----
+
+If you use Spring Boot, then your Camel routes and route configurations can be auto-discovered
+by the spring boot component scanning. This requires to add `@Component` annotation to the class.
+
+See the example https://github.com/apache/camel-spring-boot-examples/tree/main/routes-configuration[camel-example-spring-boot-routes-configuration].
+
+
+=== Route configuration with Endpoint DSL
+
+The xref:Endpoint-dsl.adoc[Endpoint DSL] can also be used for route configurations.
+This requires to add `camel-endpointdsl` to the classpath, and then use
+`org.apache.camel.builder.endpoint.EndpointRouteConfigurationBuilder`,
+which offers the _type safe_ DSL for Camel endpoints.
+
+
+== Default route configurations
+
+Route configurations are either given an explicit unique ID, or the configuration is _nameless_.
+A _nameless_ configuration is used as default/fallback configuration, for routes which has *NOT*
+been explicit assigned route configurations.
+
+Suppose you have one _nameless_ configuration and another named _javaError_:
+
+[source,java]
+----
+public class MyJavaErrorHandler extends RouteConfigurationBuilder {
+
+    @Override
+    public void configuration() throws Exception {
+        routeConfiguration()
+            .onException(Exception.class).handled(true)
+            .log("WARN: ${exception.message}");
+
+        routeConfiguration("retryError")
+            .onException(Exception.class).maximumRedeliveries(5);
+    }
+}
+----
+
+And the follow two routes:
+
+[source,java]
+----
+   from("file:cheese").routeId("cheese")
+        .to("kafka:cheese");
+
+   from("file:beer").routeId("beer")
+        .routeConfigurationId("retryError")
+        .to("jms:beer");
+----
+
+In the example above, then the _cheese_ route has no route configurations assigned, so the route
+will use the default configuration, which in case of an exception will log a warning.
+
+The _beer_ route on the other hand have route configuration _retryError_ assigned, and this
+configuration will in case of an exception retry again up till 5 times and then if still an error
+then fail and rollback.
+
+If you add more routes, then those routes can also be assigned the _retryError_ configuration
+if they should also retry in case of error.
+
+
+== Route Configuration in XML
+
+When using XML DSL then you can code your route configurations in XML files as shown below:
+
+[source,xml]
+----
+<routeConfiguration id="xmlError">
+    <onException>
+        <exception>java.lang.Exception</exception>
+        <handled><constant>true</constant></handled>
+        <log message="XML WARN: ${exception.message}"/>
+    </onException>
+</routeConfiguration>
+----
+
+And in the XML routes you can assign which configurations to use:
+
+[source,xml]
+----
+<route routeConfigurationId="xmlError">
+    <from uri="timer:xml?period=5s"/>
+    <log message="I am XML"/>
+    <throwException exceptionType="java.lang.Exception" message="Some kind of XML error"/>
+</route>
+----
+
+In this example the route is assigned the _xmlError_ route configuration by the exact ID.
+
+
+== Route Configuration in YAML
+
+When using YAML DSL then you can code your route configurations in YAML files as shown below:
+
+[source,yaml]
+----
+- route-configuration:
+    - id: "yamlError"
+    - on-exception:
+        handled:
+          constant: "true"
+        exception:
+          - "java.lang.Exception"
+        steps:
+          - log:
+              message: "YAML WARN ${exception.message}"
+----
+
+And in the YAML routes you can assign which configurations to use:
+
+[source,yaml]
+----
+- route:
+    # refer to the route configuration by the id to use for this route
+    route-configuration-id: "yamlError"
+    from: "timer:yaml?period=3s"
+    steps:
+      - set-body:
+          simple: "Timer fired ${header.CamelTimerCounter} times"
+      - to:
+          uri: "log:yaml"
+          parameters:
+            show-body-type: false
+            show-exchange-pattern: false
+      - throw-exception:
+          exception-type: "java.lang.IllegalArgumentException"
+          message: "Error from yaml"
+----
+
+In this example the route is assigned the _yamlError_ route configuration by the exact ID.
+
+== Mixing DSLs
+
+Routes and route configuration is not requires to use the same language. For example you can code
+route configurations in Java, and then use XML DSL for the routes, and they would work together.
+
+== Packaging route configurations in reusable JARs
+
+You can package common route configurations into JARs which you can then use together with
+your Camel applications, by adding the JARs as dependencies to the classpath (such as in Maven pom.xml file).
+
+This allows for example to use a _common practice_ among your Camel applications.
+
+== Logging Summary
+
+If you set `startup-summary-level=verbose` then Camel will log on for each route which route configurations they have been assigned.
+
+This option can be configured via Java API and also in `application.properties` for Camel on Spring Boot, Quarkus, and Camel standalone via `camel-main`
+
+[source,java]
+----
+camelContext.setStartupSummaryLevel(StartupSummaryLevel.Verbose);
+----
+
+And with Spring Boot:
+
+[source,properties]
+----
+camel.spring-boot.startup-summary-level = verbose
+----
+
+And in Camel Main / Quarkus:
+
+[source,properties]
+----
+camel.main.startup-summary-level = verbose
+----
+
+== See Also
+
+See the examples:
+
+- https://github.com/apache/camel-examples/tree/main/examples/routes-configuration[camel-example-routes-configuration]
+- https://github.com/apache/camel-spring-boot-examples/tree/main/routes-configuration[camel-example-spring-boot-routes-configuration]
+
diff --git a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
index 021d007..b0b846e 100644
--- a/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
+++ b/dsl/camel-dsl-support/src/main/java/org/apache/camel/dsl/support/RouteBuilderLoaderSupport.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.dsl.support;
 
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.StartupStep;
@@ -57,6 +58,7 @@ public abstract class RouteBuilderLoaderSupport extends RoutesBuilderLoaderSuppo
     @Override
     public RoutesBuilder loadRoutesBuilder(Resource resource) throws Exception {
         final RouteBuilder builder = doLoadRouteBuilder(resource);
+        CamelContextAware.trySetCamelContext(builder, getCamelContext());
 
         if (recorder != null) {
             StartupStep step = recorder.beginStep(
diff --git a/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java b/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
index 816b71a..27cab1d 100644
--- a/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
+++ b/dsl/camel-xml-io-dsl/src/main/java/org/apache/camel/dsl/xml/io/XmlRoutesBuilderLoader.java
@@ -18,11 +18,15 @@ package org.apache.camel.dsl.xml.io;
 
 import java.io.InputStream;
 
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
 import org.apache.camel.dsl.support.RouteBuilderLoaderSupport;
+import org.apache.camel.model.ModelCamelContext;
+import org.apache.camel.model.RouteConfigurationDefinition;
+import org.apache.camel.model.RouteConfigurationsDefinition;
 import org.apache.camel.model.RouteDefinition;
-import org.apache.camel.model.RouteDefinitionHelper;
 import org.apache.camel.model.RoutesDefinition;
 import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.annotations.RoutesLoader;
@@ -40,7 +44,7 @@ public class XmlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
 
     @Override
     public RouteBuilder doLoadRouteBuilder(Resource resource) throws Exception {
-        return new RouteBuilder() {
+        return new RouteConfigurationBuilder() {
             @Override
             public void configure() throws Exception {
                 // we use configure to load the routes (with namespace and without namespace)
@@ -76,14 +80,30 @@ public class XmlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
                 }
             }
 
+            @Override
+            public void configuration() throws Exception {
+                try (InputStream is = resource.getInputStream()) {
+                    new ModelParser(is)
+                            .parseRouteConfigurationsDefinition()
+                            .ifPresent(this::addConfigurations);
+                }
+            }
+
             private void addRoutes(RoutesDefinition routes) {
-                // xml routes must be marked as un-prepared as camel-core
-                // must do special handling for XML DSL
+                CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
+
+                // xml routes must be prepared in the same way java-dsl (via RoutesDefinition)
+                // so create a copy and use the fluent builder to add the route
                 for (RouteDefinition route : routes.getRoutes()) {
-                    RouteDefinitionHelper.prepareRoute(getCamelContext(), route);
-                    route.markPrepared();
+                    getRouteCollection().route(route);
+                }
+            }
+
+            private void addConfigurations(RouteConfigurationsDefinition configurations) {
+                CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
+                for (RouteConfigurationDefinition config : configurations.getRouteConfigurations()) {
+                    getCamelContext().adapt(ModelCamelContext.class).addRouteConfiguration(config);
                 }
-                setRouteCollection(routes);
             }
         };
     }
diff --git a/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java b/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
index c07a26b..024ac43 100644
--- a/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
+++ b/dsl/camel-xml-jaxb-dsl/src/main/java/org/apache/camel/dsl/xml/jaxb/JaxbXmlRoutesBuilderLoader.java
@@ -18,11 +18,11 @@ package org.apache.camel.dsl.xml.jaxb;
 
 import java.io.InputStream;
 
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.dsl.support.RouteBuilderLoaderSupport;
 import org.apache.camel.model.RouteDefinition;
-import org.apache.camel.model.RouteDefinitionHelper;
 import org.apache.camel.model.RouteTemplatesDefinition;
 import org.apache.camel.model.RoutesDefinition;
 import org.apache.camel.model.rest.RestsDefinition;
@@ -65,15 +65,12 @@ public class JaxbXmlRoutesBuilderLoader extends RouteBuilderLoaderSupport {
                 try (InputStream is = resource.getInputStream()) {
                     RoutesDefinition routes = loadRoutesDefinition(getCamelContext(), is);
                     if (routes != null) {
-                        // xml routes must be marked as un-prepared as camel-core
-                        // must do special handling for XML DSL
+                        CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
+                        // xml routes must be prepared in the same way java-dsl (via RoutesDefinition)
+                        // so create a copy and use the fluent builder to add the route
                         for (RouteDefinition route : routes.getRoutes()) {
-                            RouteDefinitionHelper.prepareRoute(getCamelContext(), route);
-                            route.markPrepared();
+                            getRouteCollection().route(route);
                         }
-
-                        routes.getRoutes().forEach(RouteDefinition::markUnprepared);
-                        setRouteCollection(routes);
                     }
                 }
             }
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml
index 3ccadeb..876ef1c 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/pom.xml
@@ -134,6 +134,8 @@
                                 <bannedDefinition>org.apache.camel.model.RouteTemplateBeanDefinition</bannedDefinition>
                                 <bannedDefinition>org.apache.camel.model.RoutesDefinition</bannedDefinition>
                                 <bannedDefinition>org.apache.camel.model.RestsDefinition</bannedDefinition>
+                                <bannedDefinition>org.apache.camel.model.RouteConfigurationDefinition</bannedDefinition>
+                                <bannedDefinition>org.apache.camel.model.RouteConfigurationsDefinition</bannedDefinition>
                             </bannedDefinitions>
                             <additionalDefinitions>
                                 <!-- saga -->
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java
index 08ac067..b69ff69 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/CustomResolver.java
@@ -38,6 +38,9 @@ public class CustomResolver implements YamlDeserializerResolver {
             case "route":
             case "org.apache.camel.model.RouteDefinition":
                 return new RouteDefinitionDeserializer();
+            case "route-configuration":
+            case "org.apache.camel.model.RouteConfigurationDefinition":
+                return new RouteConfigurationDefinitionDeserializer();
             case "template":
             case "org.apache.camel.model.RouteTemplateDefinition":
                 return new RouteTemplateDefinitionDeserializer();
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java
new file mode 100644
index 0000000..9311269
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteConfigurationDefinitionDeserializer.java
@@ -0,0 +1,93 @@
+package org.apache.camel.dsl.yaml.deserializers;
+
+import org.apache.camel.dsl.yaml.common.YamlDeserializationContext;
+import org.apache.camel.dsl.yaml.common.YamlDeserializerBase;
+import org.apache.camel.dsl.yaml.common.YamlDeserializerResolver;
+import org.apache.camel.model.InterceptDefinition;
+import org.apache.camel.model.InterceptFromDefinition;
+import org.apache.camel.model.InterceptSendToEndpointDefinition;
+import org.apache.camel.model.OnCompletionDefinition;
+import org.apache.camel.model.OnExceptionDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
+import org.apache.camel.spi.annotations.YamlProperty;
+import org.apache.camel.spi.annotations.YamlType;
+import org.snakeyaml.engine.v2.nodes.MappingNode;
+import org.snakeyaml.engine.v2.nodes.Node;
+import org.snakeyaml.engine.v2.nodes.NodeTuple;
+import org.snakeyaml.engine.v2.nodes.SequenceNode;
+
+@YamlType(
+          inline = true,
+          types = org.apache.camel.model.RouteConfigurationDefinition.class,
+          order = YamlDeserializerResolver.ORDER_DEFAULT,
+          nodes = "route-configuration",
+          properties = {
+                  @YamlProperty(name = "id", type = "string"),
+                  @YamlProperty(name = "intercept", type = "array:org.apache.camel.model.InterceptDefinition"),
+                  @YamlProperty(name = "intercept-from", type = "array:org.apache.camel.model.InterceptFromDefinition"),
+                  @YamlProperty(name = "intercept-send-to-endpoint",
+                                type = "array:org.apache.camel.model.InterceptSendToEndpointDefinition"),
+                  @YamlProperty(name = "on-completion", type = "array:org.apache.camel.model.OnCompletionDefinition"),
+                  @YamlProperty(name = "on-exception", type = "array:org.apache.camel.model.OnExceptionDefinition")
+          })
+public class RouteConfigurationDefinitionDeserializer extends YamlDeserializerBase<RouteConfigurationDefinition> {
+    public RouteConfigurationDefinitionDeserializer() {
+        super(RouteConfigurationDefinition.class);
+    }
+
+    @Override
+    protected RouteConfigurationDefinition newInstance() {
+        return new RouteConfigurationDefinition();
+    }
+
+    @Override
+    public Object construct(Node node) {
+        final RouteConfigurationDefinition target = newInstance();
+
+        final YamlDeserializationContext dc = getDeserializationContext(node);
+        final SequenceNode sn = asSequenceNode(node);
+        for (Node item : sn.getValue()) {
+            final MappingNode bn = asMappingNode(item);
+            setDeserializationContext(item, dc);
+
+            for (NodeTuple tuple : bn.getValue()) {
+                final String key = asText(tuple.getKeyNode());
+                final Node val = tuple.getValueNode();
+                switch (key) {
+                    case "id": {
+                        target.setId(asText(val));
+                        break;
+                    }
+                    case "on-exception":
+                        setDeserializationContext(val, dc);
+                        OnExceptionDefinition oed = asType(val, OnExceptionDefinition.class);
+                        target.getOnExceptions().add(oed);
+                        break;
+                    case "on-completion":
+                        setDeserializationContext(val, dc);
+                        OnCompletionDefinition ocd = asType(val, OnCompletionDefinition.class);
+                        target.getOnCompletions().add(ocd);
+                        break;
+                    case "intercept":
+                        setDeserializationContext(val, dc);
+                        InterceptDefinition id = asType(val, InterceptDefinition.class);
+                        target.getIntercepts().add(id);
+                        break;
+                    case "intercept-from":
+                        setDeserializationContext(val, dc);
+                        InterceptFromDefinition ifd = asType(val, InterceptFromDefinition.class);
+                        target.getInterceptFroms().add(ifd);
+                        break;
+                    case "intercept-send-to-endpoint":
+                        setDeserializationContext(val, dc);
+                        InterceptSendToEndpointDefinition isted = asType(val, InterceptSendToEndpointDefinition.class);
+                        target.getInterceptSendTos().add(isted);
+                        break;
+                }
+            }
+        }
+
+        return target;
+    }
+
+}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java
index 9170fcb..da7ca89 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java
@@ -37,6 +37,7 @@ import org.snakeyaml.engine.v2.nodes.NodeTuple;
           properties = {
                   @YamlProperty(name = "id", type = "string"),
                   @YamlProperty(name = "group", type = "string"),
+                  @YamlProperty(name = "route-configuration-id", type = "string"),
                   @YamlProperty(name = "from", type = "object:org.apache.camel.model.FromDefinition", required = true),
                   @YamlProperty(name = "steps", type = "array:org.apache.camel.model.ProcessorDefinition", required = true)
           })
@@ -70,6 +71,9 @@ public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefin
                 case "group":
                     target.setGroup(asText(val));
                     break;
+                case "route-configuration-id":
+                    target.setRouteConfigurationId(asText(val));
+                    break;
                 case "from":
                     target.setInput(asType(val, FromDefinition.class));
                     break;
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
index 39f7343..10e7ac6 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json
@@ -2035,6 +2035,48 @@
         } ],
         "required" : [ "ref" ]
       },
+      "org.apache.camel.model.RouteConfigurationDefinition" : {
+        "oneOf" : [ {
+          "type" : "string"
+        }, {
+          "type" : "object",
+          "properties" : {
+            "id" : {
+              "type" : "string"
+            },
+            "intercept" : {
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/items/definitions/org.apache.camel.model.InterceptDefinition"
+              }
+            },
+            "intercept-from" : {
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/items/definitions/org.apache.camel.model.InterceptFromDefinition"
+              }
+            },
+            "intercept-send-to-endpoint" : {
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/items/definitions/org.apache.camel.model.InterceptSendToEndpointDefinition"
+              }
+            },
+            "on-completion" : {
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/items/definitions/org.apache.camel.model.OnCompletionDefinition"
+              }
+            },
+            "on-exception" : {
+              "type" : "array",
+              "items" : {
+                "$ref" : "#/items/definitions/org.apache.camel.model.OnExceptionDefinition"
+              }
+            }
+          }
+        } ]
+      },
       "org.apache.camel.model.RouteContextRefDefinition" : {
         "type" : "object",
         "properties" : {
@@ -2056,6 +2098,9 @@
           "id" : {
             "type" : "string"
           },
+          "route-configuration-id" : {
+            "type" : "string"
+          },
           "steps" : {
             "type" : "array",
             "items" : {
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
index d16728d..50348b5 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
@@ -16,11 +16,14 @@
  */
 package org.apache.camel.dsl.yaml;
 
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.builder.ErrorHandlerBuilder;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.builder.RouteConfigurationBuilder;
 import org.apache.camel.dsl.yaml.deserializers.OutputAwareFromDefinition;
 import org.apache.camel.model.OnExceptionDefinition;
+import org.apache.camel.model.RouteConfigurationDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteTemplateDefinition;
 import org.apache.camel.model.rest.RestConfigurationDefinition;
@@ -42,7 +45,7 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
     }
 
     protected RouteBuilder builder(Node root) {
-        return new RouteBuilder() {
+        return new RouteConfigurationBuilder() {
             @Override
             public void configure() throws Exception {
                 for (Node node : asSequenceNode(root).getValue()) {
@@ -52,8 +55,11 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
                         RouteDefinition route = new RouteDefinition();
                         route.setInput(((OutputAwareFromDefinition) item).getDelegate());
                         route.setOutputs(((OutputAwareFromDefinition) item).getOutputs());
+
+                        CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
                         getRouteCollection().route(route);
                     } else if (item instanceof RouteDefinition) {
+                        CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
                         getRouteCollection().route((RouteDefinition) item);
                     } else if (item instanceof CamelContextCustomizer) {
                         ((CamelContextCustomizer) item).configure(getCamelContext());
@@ -62,6 +68,7 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
                             throw new IllegalArgumentException(
                                     "onException must be defined before any routes in the RouteBuilder");
                         }
+                        CamelContextAware.trySetCamelContext(getRouteCollection(), getCamelContext());
                         getRouteCollection().getOnExceptions().add((OnExceptionDefinition) item);
                     } else if (item instanceof ErrorHandlerBuilder) {
                         if (!getRouteCollection().getRoutes().isEmpty()) {
@@ -70,12 +77,14 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
                         }
                         errorHandler((ErrorHandlerBuilder) item);
                     } else if (item instanceof RouteTemplateDefinition) {
+                        CamelContextAware.trySetCamelContext(getRouteTemplateCollection(), getCamelContext());
                         getRouteTemplateCollection().routeTemplate((RouteTemplateDefinition) item);
                     } else if (item instanceof RestDefinition) {
                         RestDefinition definition = (RestDefinition) item;
                         for (VerbDefinition verb : definition.getVerbs()) {
                             verb.setRest(definition);
                         }
+                        CamelContextAware.trySetCamelContext(getRestCollection(), getCamelContext());
                         getRestCollection().rest(definition);
                     } else if (item instanceof RestConfigurationDefinition) {
                         ((RestConfigurationDefinition) item).asRestConfiguration(
@@ -84,6 +93,17 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
                     }
                 }
             }
+
+            @Override
+            public void configuration() throws Exception {
+                for (Node node : asSequenceNode(root).getValue()) {
+                    Object item = getDeserializationContext().mandatoryResolve(node).construct(node);
+                    if (item instanceof RouteConfigurationDefinition) {
+                        CamelContextAware.trySetCamelContext(getRouteConfigurationCollection(), getCamelContext());
+                        getRouteConfigurationCollection().routeConfiguration((RouteConfigurationDefinition) item);
+                    }
+                }
+            }
         };
     }
 
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy
new file mode 100644
index 0000000..15550bf
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RouteConfigurationTest.groovy
@@ -0,0 +1,169 @@
+/*
+ * 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.dsl.yaml
+
+import org.apache.camel.Exchange
+import org.apache.camel.component.mock.MockEndpoint
+import org.apache.camel.dsl.yaml.support.YamlTestSupport
+import org.apache.camel.dsl.yaml.support.model.MyException
+import org.apache.camel.dsl.yaml.support.model.MyFailingProcessor
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.Disabled
+
+class RouteConfigurationTest extends YamlTestSupport {
+    def "route-configuration"() {
+        setup:
+        loadRoutes """
+                - beans:
+                  - name: myFailingProcessor
+                    type: ${MyFailingProcessor.name}
+                - route-configuration:
+                    - on-exception:
+                        handled:
+                          constant: "true"
+                        exception:
+                          - ${MyException.name}
+                        steps:
+                          - transform:
+                              constant: "Sorry"
+                          - to: "mock:on-exception"  
+                - from:
+                    uri: "direct:start"
+                    steps:
+                      - process: 
+                          ref: "myFailingProcessor"            
+            """
+
+        withMock('mock:on-exception') {
+            expectedBodiesReceived 'Sorry'
+        }
+
+        when:
+        context.start()
+
+        withTemplate {
+            to('direct:start').withBody('hello').send()
+        }
+        then:
+        MockEndpoint.assertIsSatisfied(context)
+    }
+
+    def "route-configuration-separate"() {
+        setup:
+        // global configurations
+        loadRoutes """
+                - beans:
+                  - name: myFailingProcessor
+                    type: ${MyFailingProcessor.name}
+                - route-configuration:
+                    - on-exception:
+                        handled:
+                          constant: "true"
+                        exception:
+                          - ${MyException.name}
+                        steps:
+                          - transform:
+                              constant: "Sorry"
+                          - to: "mock:on-exception"  
+            """
+        // routes
+        loadRoutes """
+                - from:
+                    uri: "direct:start"
+                    steps:
+                      - process: 
+                          ref: "myFailingProcessor"            
+                - from:
+                    uri: "direct:start2"
+                    steps:
+                      - process: 
+                          ref: "myFailingProcessor"            
+            """
+
+        withMock('mock:on-exception') {
+            expectedBodiesReceived 'Sorry', 'Sorry'
+        }
+
+        when:
+        context.start()
+
+        withTemplate {
+            to('direct:start').withBody('hello').send()
+            to('direct:start2').withBody('hello2').send()
+        }
+        then:
+        MockEndpoint.assertIsSatisfied(context)
+    }
+
+    def "route-configuration-id"() {
+        setup:
+        // global configurations
+        loadRoutes """
+                - beans:
+                  - name: myFailingProcessor
+                    type: ${MyFailingProcessor.name}
+                - route-configuration:
+                    - id: handleError
+                    - on-exception:
+                        handled:
+                          constant: "true"
+                        exception:
+                          - ${MyException.name}
+                        steps:
+                          - transform:
+                              constant: "Sorry"
+                          - to: "mock:on-exception"  
+            """
+        // routes
+        loadRoutes """
+                - route:
+                    route-configuration-id: handleError 
+                    from:
+                        uri: "direct:start"
+                    steps:
+                      - process: 
+                          ref: "myFailingProcessor"            
+                - route:
+                    from:
+                        uri: "direct:start2"
+                    steps:
+                      - process: 
+                          ref: "myFailingProcessor"            
+            """
+
+        withMock('mock:on-exception') {
+            expectedBodiesReceived 'Sorry'
+        }
+
+        when:
+        context.start()
+
+        Exchange out1
+        Exchange out2
+        withTemplate {
+            out1 = to('direct:start').withBody('hello').send()
+            out2 = to('direct:start2').withBody('hello2').send()
+        }
+
+        then:
+        MockEndpoint.assertIsSatisfied(context)
+
+        Assertions.assertFalse(out1.isFailed())
+        Assertions.assertTrue(out2.isFailed())
+    }
+
+}
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelXmlParserGeneratorMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelXmlParserGeneratorMojo.java
index bfc4cece..601dbf3 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelXmlParserGeneratorMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/ModelXmlParserGeneratorMojo.java
@@ -101,6 +101,7 @@ public class ModelXmlParserGeneratorMojo extends AbstractGeneratorMojo {
     private Class<?> outputDefinitionClass;
     private Class<?> expressionDefinitionClass;
     private Class<?> routesDefinitionClass;
+    private Class<?> routeConfigurationsDefinitionClass;
     private Class<?> routeTemplatesDefinitionClass;
     private Class<?> restsDefinitionClass;
     private Class<?> processorDefinitionClass;
@@ -134,6 +135,7 @@ public class ModelXmlParserGeneratorMojo extends AbstractGeneratorMojo {
 
         outputDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".OutputDefinition");
         routesDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".RoutesDefinition");
+        routeConfigurationsDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".RouteConfigurationsDefinition");
         routeTemplatesDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".RouteTemplatesDefinition");
         dataFormatDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".DataFormatDefinition");
         processorDefinitionClass = loadClass(classLoader, MODEL_PACKAGE + ".ProcessorDefinition");
@@ -476,7 +478,7 @@ public class ModelXmlParserGeneratorMojo extends AbstractGeneratorMojo {
                 }
                 return " noValueHandler()";
             });
-            if (clazz == routesDefinitionClass || clazz == routeTemplatesDefinitionClass || clazz == restsDefinitionClass) {
+            if (clazz == routesDefinitionClass || clazz == routeTemplatesDefinitionClass || clazz == restsDefinitionClass || clazz == routeConfigurationsDefinitionClass) {
 
                 // for routes/rests/routeTemplates we want to support single-mode as well, this means
                 // we check that the tag name is either plural or singular and parse accordingly