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 2019/10/17 19:09:25 UTC

[camel] 04/09: CAMEL-14050: camel-main - Add logic for automatic RouteBuilder class detection ala camel-spring-boot has

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

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

commit 5b1147bd47c18a7b57984788b36658db90a301d8
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Oct 17 17:20:49 2019 +0200

    CAMEL-14050: camel-main - Add logic for automatic RouteBuilder class detection ala camel-spring-boot has
---
 .../src/main/docs/spring-boot.adoc                 |  3 +-
 .../camel/spring/boot/CamelAutoConfiguration.java  |  8 +-
 .../spring/boot/CamelConfigurationProperties.java  | 10 +++
 ...ava => CamelSpringBootApplicationListener.java} | 75 ++++++-------------
 .../spring/boot/SpringBootRoutesCollector.java     | 11 ++-
 .../boot/parent/SpringBootRefreshContextTest.java  |  4 +-
 .../org/apache/camel/main/BaseRoutesCollector.java | 45 +++++------
 .../camel/main/DefaultConfigurationProperties.java | 30 ++++++++
 .../org/apache/camel/main/RoutesCollector.java     | 37 +++++++--
 .../org/apache/camel/main/RoutesConfigurer.java    | 87 ++++++++++++++++++++++
 .../camel-main-configuration-metadata.json         |  7 ++
 11 files changed, 224 insertions(+), 93 deletions(-)

diff --git a/components/camel-spring-boot/src/main/docs/spring-boot.adoc b/components/camel-spring-boot/src/main/docs/spring-boot.adoc
index 73a8678..89a5c30 100644
--- a/components/camel-spring-boot/src/main/docs/spring-boot.adoc
+++ b/components/camel-spring-boot/src/main/docs/spring-boot.adoc
@@ -89,7 +89,7 @@ When using Spring Boot make sure to use the following Maven dependency to have s
 ----
 
 
-The component supports 139 options, which are listed below.
+The component supports 140 options, which are listed below.
 
 
 
@@ -182,6 +182,7 @@ The component supports 139 options, which are listed below.
 | *camel.springboot.producer-template-cache-size* | Producer template endpoints cache size. | 1000 | Integer
 | *camel.springboot.route-filter-exclude-pattern* | Used for filtering routes routes matching the given pattern, which follows the following rules: - Match by route id - Match by route input endpoint uri The matching is using exact match, by wildcard and regular expression. For example to only include routes which starts with foo in their route id's, use: include=foo&#42; And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42; Multiple patterns can be separated by c [...]
 | *camel.springboot.route-filter-include-pattern* | Used for filtering routes routes matching the given pattern, which follows the following rules: - Match by route id - Match by route input endpoint uri The matching is using exact match, by wildcard and regular expression. For example to only include routes which starts with foo in their route id's, use: include=foo&#42; And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42; Multiple patterns can be separated by c [...]
+| *camel.springboot.routes-collector-enabled* | Whether the routes collector is enabled or not. When enabled Camel will auto-discover routes (RouteBuilder instances from the registry and also load additional XML routes from the file system. The routes collector is default enabled. | true | Boolean
 | *camel.springboot.shutdown-log-inflight-exchanges-on-timeout* | Sets whether to log information about the inflight Exchanges which are still running during a shutdown which didn't complete without the given timeout. | true | Boolean
 | *camel.springboot.shutdown-now-on-timeout* | Sets whether to force shutdown of all consumers when a timeout occurred and thus not all consumers was shutdown within that period. You should have good reasons to set this option to false as it means that the routes keep running and is halted abruptly when CamelContext has been shutdown. | true | Boolean
 | *camel.springboot.shutdown-routes-in-reverse-order* | Sets whether routes should be shutdown in reverse or the same order as they where started. | true | Boolean
diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java
index c155230..b1c73ea 100644
--- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java
+++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelAutoConfiguration.java
@@ -149,11 +149,11 @@ public class CamelAutoConfiguration {
     }
 
     @Bean
-    @ConditionalOnMissingBean(RoutesCollectorListener.class)
-    RoutesCollectorListener routesCollectorListener(ApplicationContext applicationContext, CamelConfigurationProperties config,
-                                                    RoutesCollector routesCollector) {
+    @ConditionalOnMissingBean(CamelSpringBootApplicationListener.class)
+    CamelSpringBootApplicationListener routesCollectorListener(ApplicationContext applicationContext, CamelConfigurationProperties config,
+                                                               RoutesCollector routesCollector) {
         Collection<CamelContextConfiguration> configurations = applicationContext.getBeansOfType(CamelContextConfiguration.class).values();
-        return new RoutesCollectorListener(applicationContext, new ArrayList(configurations), config, routesCollector);
+        return new CamelSpringBootApplicationListener(applicationContext, new ArrayList(configurations), config, routesCollector);
     }
 
     /**
diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java
index 8e06364..f1c36fa 100644
--- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java
+++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelConfigurationProperties.java
@@ -408,6 +408,16 @@ public class CamelConfigurationProperties extends DefaultConfigurationProperties
     private LoggingLevel beanIntrospectionLoggingLevel;
 
     /**
+     * Whether the routes collector is enabled or not.
+     *
+     * When enabled Camel will auto-discover routes (RouteBuilder instances from the registry and
+     * also load additional XML routes from the file system.
+     *
+     * The routes collector is default enabled.
+     */
+    private boolean routesCollectorEnabled = true;
+
+    /**
      * Used for inclusive filtering component scanning of RouteBuilder classes with @Component annotation.
      * The exclusive filtering takes precedence over inclusive filtering.
      * The pattern is using Ant-path style pattern.
diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/RoutesCollectorListener.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelSpringBootApplicationListener.java
similarity index 80%
rename from components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/RoutesCollectorListener.java
rename to components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelSpringBootApplicationListener.java
index 0c7c4fc..ed0eca1 100644
--- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/RoutesCollectorListener.java
+++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelSpringBootApplicationListener.java
@@ -25,18 +25,14 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.camel.CamelContext;
-import org.apache.camel.RoutesBuilder;
 import org.apache.camel.StartupListener;
 import org.apache.camel.main.MainDurationEventNotifier;
 import org.apache.camel.main.RoutesCollector;
-import org.apache.camel.model.Model;
-import org.apache.camel.model.RoutesDefinition;
-import org.apache.camel.model.rest.RestsDefinition;
+import org.apache.camel.main.RoutesConfigurer;
 import org.apache.camel.spi.CamelEvent;
 import org.apache.camel.spi.CamelEvent.Type;
 import org.apache.camel.spi.EventNotifier;
 import org.apache.camel.support.EventNotifierSupport;
-import org.apache.camel.support.OrderedComparator;
 import org.apache.camel.support.service.ServiceHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -47,30 +43,31 @@ import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.core.Ordered;
 
 /**
- * Collects routes and rests from the various sources (like Spring application context beans registry or opinionated
+ * A spring application listener that when spring boot is starting (refresh event) will setup Camel by:
+ * <p>
+ * 1. collecting routes and rests from the various sources (like Spring application context beans registry or opinionated
  * classpath locations) and injects these into the Camel context.
+ * 2. setting up Camel main controller if enabled.
+ * 3. setting up run duration if in use.
  */
-public class RoutesCollectorListener implements ApplicationListener<ContextRefreshedEvent>, Ordered {
+public class CamelSpringBootApplicationListener implements ApplicationListener<ContextRefreshedEvent>, Ordered {
 
     // Static collaborators
 
-    private static final Logger LOG = LoggerFactory.getLogger(RoutesCollectorListener.class);
+    private static final Logger LOG = LoggerFactory.getLogger(CamelSpringBootApplicationListener.class);
 
     // Collaborators
 
     private final ApplicationContext applicationContext;
-
     private final List<CamelContextConfiguration> camelContextConfigurations;
-
     private final CamelConfigurationProperties configurationProperties;
-
     private final RoutesCollector springBootRoutesCollector;
 
     // Constructors
 
-    public RoutesCollectorListener(ApplicationContext applicationContext, List<CamelContextConfiguration> camelContextConfigurations,
-                                   CamelConfigurationProperties configurationProperties,
-                                   RoutesCollector springBootRoutesCollector) {
+    public CamelSpringBootApplicationListener(ApplicationContext applicationContext, List<CamelContextConfiguration> camelContextConfigurations,
+                                              CamelConfigurationProperties configurationProperties,
+                                              RoutesCollector springBootRoutesCollector) {
         this.applicationContext = applicationContext;
         this.camelContextConfigurations = new ArrayList<>(camelContextConfigurations);
         this.configurationProperties = configurationProperties;
@@ -88,42 +85,18 @@ public class RoutesCollectorListener implements ApplicationListener<ContextRefre
                 && camelContext.getStatus().isStopped()) {
             LOG.debug("Post-processing CamelContext bean: {}", camelContext.getName());
 
-            final List<RoutesBuilder> routes = springBootRoutesCollector.collectRoutesFromRegistry(camelContext, configurationProperties);
+            if (configurationProperties.isRoutesCollectorEnabled()) {
+                LOG.debug("RoutesCollectorEnabled: {}", springBootRoutesCollector);
+                RoutesConfigurer configurer = new RoutesConfigurer(springBootRoutesCollector);
+                configurer.configureRoutes(camelContext, configurationProperties);
+            }
 
-            // sort routes according to ordered
-            routes.sort(OrderedComparator.get());
-            // then add the routes
-            for (RoutesBuilder routesBuilder : routes) {
-                try {
-                    LOG.debug("Injecting following route into the CamelContext: {}", routesBuilder);
-                    camelContext.addRoutes(routesBuilder);
-                } catch (Exception e) {
-                    throw new CamelSpringBootInitializationException(e);
-                }
+            for (CamelContextConfiguration camelContextConfiguration : camelContextConfigurations) {
+                LOG.debug("CamelContextConfiguration found. Invoking beforeApplicationStart: {}", camelContextConfiguration);
+                camelContextConfiguration.beforeApplicationStart(camelContext);
             }
 
             try {
-                boolean scan = !configurationProperties.getXmlRoutes().equals("false");
-                if (scan) {
-                    List<RoutesDefinition> defs = springBootRoutesCollector.collectXmlRoutesFromDirectory(camelContext, configurationProperties.getXmlRoutes());
-                    for (RoutesDefinition def : defs) {
-                        camelContext.getExtension(Model.class).addRouteDefinitions(def.getRoutes());
-                    }
-                }
-
-                boolean scanRests = !configurationProperties.getXmlRests().equals("false");
-                if (scanRests) {
-                    List<RestsDefinition> defs = springBootRoutesCollector.collectXmlRestsFromDirectory(camelContext, configurationProperties.getXmlRests());
-                    for (RestsDefinition def : defs) {
-                        camelContext.getExtension(Model.class).addRestDefinitions(def.getRests(), true);
-                    }
-                }
-
-                for (CamelContextConfiguration camelContextConfiguration : camelContextConfigurations) {
-                    LOG.debug("CamelContextConfiguration found. Invoking beforeApplicationStart: {}", camelContextConfiguration);
-                    camelContextConfiguration.beforeApplicationStart(camelContext);
-                }
-
                 if (configurationProperties.isMainRunController()) {
                     CamelMainRunController controller = new CamelMainRunController(applicationContext, camelContext);
 
@@ -136,8 +109,8 @@ public class RoutesCollectorListener implements ApplicationListener<ContextRefre
                         }
                         // register lifecycle so we can trigger to shutdown the JVM when maximum number of messages has been processed
                         EventNotifier notifier = new MainDurationEventNotifier(camelContext,
-                            configurationProperties.getDurationMaxMessages(), configurationProperties.getDurationMaxIdleSeconds(),
-                            controller.getCompleted(), controller.getLatch(), true);
+                                configurationProperties.getDurationMaxMessages(), configurationProperties.getDurationMaxIdleSeconds(),
+                                controller.getCompleted(), controller.getLatch(), true);
                         // register our event notifier
                         ServiceHelper.startService(notifier);
                         camelContext.getManagementStrategy().addEventNotifier(notifier);
@@ -146,7 +119,7 @@ public class RoutesCollectorListener implements ApplicationListener<ContextRefre
                     if (configurationProperties.getDurationMaxSeconds() > 0) {
                         LOG.info("CamelSpringBoot will terminate after {} seconds", configurationProperties.getDurationMaxSeconds());
                         terminateMainControllerAfter(camelContext, configurationProperties.getDurationMaxSeconds(),
-                            controller.getCompleted(), controller.getLatch());
+                                controller.getCompleted(), controller.getLatch());
                     }
 
                     camelContext.addStartupListener(new StartupListener() {
@@ -185,8 +158,8 @@ public class RoutesCollectorListener implements ApplicationListener<ContextRefre
 
                             // register lifecycle so we can trigger to shutdown the JVM when maximum number of messages has been processed
                             EventNotifier notifier = new MainDurationEventNotifier(camelContext,
-                                configurationProperties.getDurationMaxMessages(), configurationProperties.getDurationMaxIdleSeconds(),
-                                completed, latch, false);
+                                    configurationProperties.getDurationMaxMessages(), configurationProperties.getDurationMaxIdleSeconds(),
+                                    completed, latch, false);
                             // register our event notifier
                             ServiceHelper.startService(notifier);
                             camelContext.getManagementStrategy().addEventNotifier(notifier);
diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SpringBootRoutesCollector.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SpringBootRoutesCollector.java
index 3f5d7d3..e2a30a1 100644
--- a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SpringBootRoutesCollector.java
+++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SpringBootRoutesCollector.java
@@ -21,7 +21,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.main.BaseRoutesCollector;
+import org.apache.camel.main.DefaultConfigurationProperties;
 import org.apache.camel.model.ModelHelper;
 import org.apache.camel.model.RoutesDefinition;
 import org.apache.camel.model.rest.RestsDefinition;
@@ -40,7 +43,7 @@ public class SpringBootRoutesCollector extends BaseRoutesCollector {
     }
 
     @Override
-    public List<RoutesDefinition> collectXmlRoutesFromDirectory(CamelContext camelContext, String directory) throws Exception {
+    public List<RoutesDefinition> collectXmlRoutesFromDirectory(CamelContext camelContext, String directory) {
         List<RoutesDefinition> answer = new ArrayList<>();
 
         String[] parts = directory.split(",");
@@ -55,6 +58,8 @@ public class SpringBootRoutesCollector extends BaseRoutesCollector {
                 }
             } catch (FileNotFoundException e) {
                 log.debug("No XML routes found in {}. Skipping XML routes detection.", part);
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
             }
         }
 
@@ -62,7 +67,7 @@ public class SpringBootRoutesCollector extends BaseRoutesCollector {
     }
 
     @Override
-    public List<RestsDefinition> collectXmlRestsFromDirectory(CamelContext camelContext, String directory) throws Exception {
+    public List<RestsDefinition> collectXmlRestsFromDirectory(CamelContext camelContext, String directory) {
         List<RestsDefinition> answer = new ArrayList<>();
 
         String[] parts = directory.split(",");
@@ -76,6 +81,8 @@ public class SpringBootRoutesCollector extends BaseRoutesCollector {
                 }
             } catch (FileNotFoundException e) {
                 log.debug("No XML rests found in {}. Skipping XML rests detection.", part);
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
             }
         }
 
diff --git a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/parent/SpringBootRefreshContextTest.java b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/parent/SpringBootRefreshContextTest.java
index 29d81a0..e8ed75d 100644
--- a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/parent/SpringBootRefreshContextTest.java
+++ b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/parent/SpringBootRefreshContextTest.java
@@ -18,7 +18,7 @@ package org.apache.camel.spring.boot.parent;
 
 import org.apache.camel.RoutesBuilder;
 import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.spring.boot.RoutesCollectorListener;
+import org.apache.camel.spring.boot.CamelSpringBootApplicationListener;
 import org.junit.Test;
 import org.springframework.boot.WebApplicationType;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -36,7 +36,7 @@ public class SpringBootRefreshContextTest {
         parent.refresh();
         ConfigurableApplicationContext context = new SpringApplicationBuilder(Configuration.class).web(WebApplicationType.NONE).parent(parent).run();
         ContextRefreshedEvent refreshEvent = new ContextRefreshedEvent(context);
-        RoutesCollectorListener collector = context.getBean(RoutesCollectorListener.class);
+        CamelSpringBootApplicationListener collector = context.getBean(CamelSpringBootApplicationListener.class);
         collector.onApplicationEvent(refreshEvent); //no changes should happen here
     }
 
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/BaseRoutesCollector.java b/core/camel-main/src/main/java/org/apache/camel/main/BaseRoutesCollector.java
index 38cbfb9..17fe2a3 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseRoutesCollector.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseRoutesCollector.java
@@ -1,13 +1,13 @@
-/**
+/*
  * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
+ *
+ *      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.
@@ -23,26 +23,23 @@ import java.util.Set;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.RoutesBuilder;
-import org.apache.camel.model.RoutesDefinition;
-import org.apache.camel.model.rest.RestsDefinition;
 import org.apache.camel.util.AntPathMatcher;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Collects routes and rests from the various sources (like registry or opinionated
- * classpath locations) and injects these into the Camel context.
+ * Base {@link RoutesCollector}.
  */
 public abstract class BaseRoutesCollector implements RoutesCollector {
 
-    // TODO: Add load routes from xml and rest
-    // TODO: Base class and extended for spring-boot etc
     // TODO: Add to camel main that it uses route collector
 
     protected final Logger log = LoggerFactory.getLogger(getClass());
 
-    public List<RoutesBuilder> collectRoutesFromRegistry(CamelContext camelContext, DefaultConfigurationProperties configurationProperties) {
+    @Override
+    public List<RoutesBuilder> collectRoutesFromRegistry(CamelContext camelContext,
+                                                         String excludePattern, String includePattern) {
         final List<RoutesBuilder> routes = new ArrayList<>();
 
         final AntPathMatcher matcher = new AntPathMatcher();
@@ -55,14 +52,11 @@ public abstract class BaseRoutesCollector implements RoutesCollector {
                 // make name as path so we can use ant path matcher
                 name = name.replace('.', '/');
 
-                String exclude = configurationProperties.getJavaRoutesExcludePattern();
-                String include = configurationProperties.getJavaRoutesIncludePattern();
-
-                boolean match = !"false".equals(include);
+                boolean match = !"false".equals(includePattern);
                 // exclude take precedence over include
-                if (match && ObjectHelper.isNotEmpty(exclude)) {
+                if (match && ObjectHelper.isNotEmpty(excludePattern)) {
                     // there may be multiple separated by comma
-                    String[] parts = exclude.split(",");
+                    String[] parts = excludePattern.split(",");
                     for (String part : parts) {
                         // must negate when excluding, and hence !
                         match = !matcher.match(part, name);
@@ -73,14 +67,14 @@ public abstract class BaseRoutesCollector implements RoutesCollector {
                     }
                 }
                 // special support for testing with @ExcludeRoutes annotation with camel-test-spring
-                exclude = System.getProperty("CamelTestSpringExcludeRoutes");
+                excludePattern = System.getProperty("CamelTestSpringExcludeRoutes");
                 // exclude take precedence over include
-                if (match && ObjectHelper.isNotEmpty(exclude)) {
+                if (match && ObjectHelper.isNotEmpty(excludePattern)) {
                     // this property is a comma separated list of FQN class names, so we need to make
                     // name as path so we can use ant patch matcher
-                    exclude = exclude.replace('.', '/');
+                    excludePattern = excludePattern.replace('.', '/');
                     // there may be multiple separated by comma
-                    String[] parts = exclude.split(",");
+                    String[] parts = excludePattern.split(",");
                     for (String part : parts) {
                         // must negate when excluding, and hence !
                         match = !matcher.match(part, name);
@@ -90,9 +84,9 @@ public abstract class BaseRoutesCollector implements RoutesCollector {
                         }
                     }
                 }
-                if (match && ObjectHelper.isNotEmpty(include)) {
+                if (match && ObjectHelper.isNotEmpty(includePattern)) {
                     // there may be multiple separated by comma
-                    String[] parts = include.split(",");
+                    String[] parts = includePattern.split(",");
                     for (String part : parts) {
                         match = matcher.match(part, name);
                         log.trace("Java RoutesBuilder: {} include filter: {} -> {}", name, part, match);
@@ -106,14 +100,9 @@ public abstract class BaseRoutesCollector implements RoutesCollector {
                     routes.add(routesBuilder);
                 }
             }
-
         }
 
         return routes;
     }
 
-    public abstract List<RoutesDefinition> collectXmlRoutesFromDirectory(CamelContext camelContext, String directory) throws Exception;
-
-    public abstract List<RestsDefinition> collectXmlRestsFromDirectory(CamelContext camelContext, String directory) throws Exception;
-
 }
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
index e8794c5..b0c0271 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultConfigurationProperties.java
@@ -71,6 +71,7 @@ public abstract class DefaultConfigurationProperties<T> {
     private String routeFilterExcludePattern;
     private boolean beanIntrospectionExtendedStatistics;
     private LoggingLevel beanIntrospectionLoggingLevel;
+    private boolean routesCollectorEnabled = true;
     private String javaRoutesIncludePattern;
     private String javaRoutesExcludePattern;
     private String xmlRoutes = "classpath:camel/*.xml";
@@ -708,6 +709,22 @@ public abstract class DefaultConfigurationProperties<T> {
         this.beanIntrospectionLoggingLevel = beanIntrospectionLoggingLevel;
     }
 
+    public boolean isRoutesCollectorEnabled() {
+        return routesCollectorEnabled;
+    }
+
+    /**
+     * Whether the routes collector is enabled or not.
+     * 
+     * When enabled Camel will auto-discover routes (RouteBuilder instances from the registry and
+     * also load additional XML routes from the file system.
+     *
+     * The routes collector is default enabled.
+     */
+    public void setRoutesCollectorEnabled(boolean routesCollectorEnabled) {
+        this.routesCollectorEnabled = routesCollectorEnabled;
+    }
+
     public String getJavaRoutesIncludePattern() {
         return javaRoutesIncludePattern;
     }
@@ -1277,6 +1294,19 @@ public abstract class DefaultConfigurationProperties<T> {
     }
 
     /**
+     * Whether the routes collector is enabled or not.
+     *
+     * When enabled Camel will auto-discover routes (RouteBuilder instances from the registry and
+     * also load additional XML routes from the file system.
+     *
+     * The routes collector is default enabled.
+     */
+    public T withRoutesCollectorEnabled(boolean routesCollectorEnabled) {
+        this.routesCollectorEnabled = routesCollectorEnabled;
+        return (T) this;
+    }
+
+    /**
      * Used for inclusive filtering component scanning of RouteBuilder classes with @Component annotation.
      * The exclusive filtering takes precedence over inclusive filtering.
      * The pattern is using Ant-path style pattern.
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/RoutesCollector.java b/core/camel-main/src/main/java/org/apache/camel/main/RoutesCollector.java
index 33fabb1..b8e9648 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/RoutesCollector.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/RoutesCollector.java
@@ -1,13 +1,13 @@
-/**
+/*
  * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
+ *
+ *      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.
@@ -23,12 +23,39 @@ import org.apache.camel.RoutesBuilder;
 import org.apache.camel.model.RoutesDefinition;
 import org.apache.camel.model.rest.RestsDefinition;
 
+/**
+ * Collects routes and rests from the various sources (like registry or opinionated
+ * classpath locations) and injects these into the Camel context.
+ */
 public interface RoutesCollector {
 
-    List<RoutesBuilder> collectRoutesFromRegistry(CamelContext camelContext, DefaultConfigurationProperties configurationProperties);
+    /**
+     * Collects the {@link RoutesBuilder} instances which was discovered from the {@link org.apache.camel.spi.Registry} such as
+     * Spring or CDI bean containers.
+     *
+     * @param camelContext        the Camel Context
+     * @param excludePattern      exclude pattern (see javaRoutesExcludePattern option)
+     * @param includePattern      include pattern  (see javaRoutesIncludePattern option)
+     * @return the discovered routes or an empty list
+     */
+    List<RoutesBuilder> collectRoutesFromRegistry(CamelContext camelContext, String excludePattern, String includePattern);
 
+    /**
+     * Collects all XML routes from the given directory.
+     *
+     * @param camelContext               the Camel Context
+     * @param directory                  the directory (see xmlRoutes option)
+     * @return the discovered routes or an empty list
+     */
     List<RoutesDefinition> collectXmlRoutesFromDirectory(CamelContext camelContext, String directory) throws Exception;
 
+    /**
+     * Collects all XML rests from the given directory.
+     *
+     * @param camelContext               the Camel Context
+     * @param directory                  the directory (see xmlRests option)
+     * @return the discovered rests or an empty list
+     */
     List<RestsDefinition> collectXmlRestsFromDirectory(CamelContext camelContext, String directory) throws Exception;
 
 }
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
new file mode 100644
index 0000000..fd18ad4
--- /dev/null
+++ b/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java
@@ -0,0 +1,87 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.main;
+
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.model.Model;
+import org.apache.camel.model.RoutesDefinition;
+import org.apache.camel.model.rest.RestsDefinition;
+import org.apache.camel.support.OrderedComparator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * To configure routes using {@link RoutesCollector} which collects the routes from various sources.
+ */
+public class RoutesConfigurer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RoutesConfigurer.class);
+
+    private final RoutesCollector routesCollector;
+
+    public RoutesConfigurer(RoutesCollector routesCollector) {
+        this.routesCollector = routesCollector;
+    }
+
+    /**
+     * Collects routes and rests from the various sources (like registry or opinionated
+     * classpath locations) and injects these into the Camel context.
+     *
+     * @param camelContext  the Camel Context
+     * @param config        the configuration
+     */
+    public void configureRoutes(CamelContext camelContext, DefaultConfigurationProperties config) {
+        if (config.isRoutesCollectorEnabled()) {
+            try {
+                LOG.debug("RoutesCollectorEnabled: {}", routesCollector);
+                final List<RoutesBuilder> routes = routesCollector.collectRoutesFromRegistry(camelContext,
+                        config.getJavaRoutesExcludePattern(),
+                        config.getJavaRoutesIncludePattern());
+
+                // sort routes according to ordered
+                routes.sort(OrderedComparator.get());
+                // then add the routes
+                for (RoutesBuilder routesBuilder : routes) {
+                    LOG.debug("Injecting following route into the CamelContext: {}", routesBuilder);
+                    camelContext.addRoutes(routesBuilder);
+                }
+
+                boolean scan = !config.getXmlRoutes().equals("false");
+                if (scan) {
+                    List<RoutesDefinition> defs = routesCollector.collectXmlRoutesFromDirectory(camelContext, config.getXmlRoutes());
+                    for (RoutesDefinition def : defs) {
+                        camelContext.getExtension(Model.class).addRouteDefinitions(def.getRoutes());
+                    }
+                }
+
+                boolean scanRests = !config.getXmlRests().equals("false");
+                if (scanRests) {
+                    List<RestsDefinition> defs = routesCollector.collectXmlRestsFromDirectory(camelContext, config.getXmlRests());
+                    for (RestsDefinition def : defs) {
+                        camelContext.getExtension(Model.class).addRestDefinitions(def.getRests(), true);
+                    }
+                }
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
+            }
+        }
+    }
+}
diff --git a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
index e0c3bfe..67616b3 100644
--- a/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
+++ b/core/camel-main/src/main/resources/META-INF/camel-main-configuration-metadata.json
@@ -249,6 +249,13 @@
 			"description":"Used for filtering routes routes matching the given pattern, which follows the following rules: - Match by route id - Match by route input endpoint uri The matching is using exact match, by wildcard and regular expression as documented by PatternHelper#matchPattern(String,String) . For example to only include routes which starts with foo in their route id's, use: include=foo&#42; And to exclude routes which starts from JMS endpoints, use: exclude=jms:&#42; Multiple patt [...]
 		},
 		{
+			"name":"camel.main.routes-collector-enabled",
+			"type":"boolean",
+			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
+			"description":"Whether the routes collector is enabled or not. When enabled Camel will auto-discover routes (RouteBuilder instances from the registry and also load additional XML routes from the file system. The routes collector is default enabled.",
+			"defaultValue":"true"
+		},
+		{
 			"name":"camel.main.shutdown-log-inflight-exchanges-on-timeout",
 			"type":"boolean",
 			"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",