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

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


The following commit(s) were added to refs/heads/master by this push:
     new f4245fc  Route collector (#3261)
f4245fc is described below

commit f4245fc989cf7800ee088b5afc73485a20e75418
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Fri Oct 18 09:31:02 2019 +0200

    Route collector (#3261)
    
    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  |  13 +-
 .../spring/boot/CamelConfigurationProperties.java  | 140 ++++++---------
 ...ava => CamelSpringBootApplicationListener.java} | 167 +++--------------
 .../spring/boot/SpringBootRoutesCollector.java     | 160 +++++++++++++++++
 .../boot/SupervisingRouteControllerTest.java       |  20 ++-
 .../boot/parent/SpringBootRefreshContextTest.java  |   4 +-
 .../java/org/apache/camel/spi/RouteContext.java    |  10 +-
 .../org/apache/camel/main/BaseMainSupport.java     |  35 +++-
 .../camel/main/DefaultConfigurationProperties.java | 199 +++++++++++++++++++++
 .../apache/camel/main/DefaultRoutesCollector.java  | 139 ++++++++++++++
 .../camel/main/MainConfigurationProperties.java    |  24 +++
 .../org/apache/camel/main/RoutesCollector.java     |  61 +++++++
 .../org/apache/camel/main/RoutesConfigurer.java    | 109 +++++++++++
 .../camel-main-configuration-metadata.json         |  39 ++++
 .../main/MainRoutesCollectorPackageScanTest.java   |  50 ++++++
 .../apache/camel/main/MainRoutesCollectorTest.java |  54 ++++++
 .../camel/main/scan/MyDummyRouteBuilder.java       |  27 +++
 .../apache/camel/main/scan/MyScanRouteBuilder.java |  27 +++
 19 files changed, 1032 insertions(+), 249 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 6a5bd55..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
@@ -29,6 +29,7 @@ import org.apache.camel.ProducerTemplate;
 import org.apache.camel.component.properties.PropertiesComponent;
 import org.apache.camel.component.properties.PropertiesParser;
 import org.apache.camel.main.DefaultConfigurationConfigurer;
+import org.apache.camel.main.RoutesCollector;
 import org.apache.camel.model.Model;
 import org.apache.camel.spi.BeanRepository;
 import org.apache.camel.spring.CamelBeanPostProcessor;
@@ -133,7 +134,6 @@ public class CamelAutoConfiguration {
         // lookup and configure SPI beans
         DefaultConfigurationConfigurer.afterPropertiesSet(camelContext);
 
-
         return camelContext;
     }
 
@@ -144,9 +144,16 @@ public class CamelAutoConfiguration {
 
     @Bean
     @ConditionalOnMissingBean(RoutesCollector.class)
-    RoutesCollector routesCollector(ApplicationContext applicationContext, 
CamelConfigurationProperties config) {
+    RoutesCollector routesCollector(ApplicationContext applicationContext) {
+        return new SpringBootRoutesCollector(applicationContext);
+    }
+
+    @Bean
+    @ConditionalOnMissingBean(CamelSpringBootApplicationListener.class)
+    CamelSpringBootApplicationListener 
routesCollectorListener(ApplicationContext applicationContext, 
CamelConfigurationProperties config,
+                                                               RoutesCollector 
routesCollector) {
         Collection<CamelContextConfiguration> configurations = 
applicationContext.getBeansOfType(CamelContextConfiguration.class).values();
-        return new RoutesCollector(applicationContext, new 
ArrayList(configurations), config);
+        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 9f33bac..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
@@ -47,56 +47,6 @@ public class CamelConfigurationProperties extends 
DefaultConfigurationProperties
      */
     private boolean warnOnEarlyShutdown = 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.
-     *
-     * Multiple patterns can be specified separated by comma.
-     * For example to include all classes starting with Foo use: 
&#42;&#42;/Foo*
-     * To include all routes form a specific package use: 
com/mycompany/foo/&#42;
-     * To include all routes form a specific package and its sub-packages use 
double wildcards: com/mycompany/foo/&#42;&#42;
-     * And to include all routes from two specific packages use: 
com/mycompany/foo/&#42;,com/mycompany/stuff/&#42;
-     */
-    private String javaRoutesIncludePattern;
-
-    /**
-     * Used for exclusive 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.
-     * Multiple patterns can be specified separated by comma.
-     *
-     * For example to exclude all classes starting with Bar use: 
&#42;&#42;/Bar&#42;
-     * To exclude all routes form a specific package use: 
com/mycompany/bar/&#42;
-     * To exclude all routes form a specific package and its sub-packages use 
double wildcards: com/mycompany/bar/&#42;&#42;
-     * And to exclude all routes from two specific packages use: 
com/mycompany/bar/&#42;,com/mycompany/stuff/&#42;
-     */
-    private String javaRoutesExcludePattern;
-
-    /**
-     * Directory to scan for adding additional XML routes.
-     * You can turn this off by setting the value to false.
-     *
-     * Files can be loaded from either classpath or file by prefixing with 
classpath: or file:
-     * Wildcards is supported using a ANT pattern style paths, such as 
classpath:&#42;&#42;/&#42;camel&#42;.xml
-     *
-     * Multiple directories can be specified and separated by comma, such as:
-     * file:/myapp/mycamel/&#42;.xml,file:/myapp/myothercamel/&#42;.xml
-     */
-    private String xmlRoutes = "classpath:camel/*.xml";
-
-    /**
-     * Directory to scan for adding additional XML rests.
-     * You can turn this off by setting the value to false.
-     *
-     * Files can be loaded from either classpath or file by prefixing with 
classpath: or file:
-     * Wildcards is supported using a ANT pattern style paths, such as 
classpath:&#42;&#42;/&#42;camel&#42;.xml
-     *
-     * Multiple directories can be specified and separated by comma, such as:
-     * file:/myapp/mycamel/&#42;.xml,file:/myapp/myothercamel/&#42;.xml
-     */
-    private String xmlRests = "classpath:camel-rest/*.xml";
-
     // Default Properties via camel-main
     // ---------------------------------
 
@@ -457,6 +407,65 @@ 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.
+     *
+     * Multiple patterns can be specified separated by comma.
+     * For example to include all classes starting with Foo use: 
&#42;&#42;/Foo*
+     * To include all routes form a specific package use: 
com/mycompany/foo/&#42;
+     * To include all routes form a specific package and its sub-packages use 
double wildcards: com/mycompany/foo/&#42;&#42;
+     * And to include all routes from two specific packages use: 
com/mycompany/foo/&#42;,com/mycompany/stuff/&#42;
+     */
+    private String javaRoutesIncludePattern;
+
+    /**
+     * Used for exclusive 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.
+     * Multiple patterns can be specified separated by comma.
+     *
+     * For example to exclude all classes starting with Bar use: 
&#42;&#42;/Bar&#42;
+     * To exclude all routes form a specific package use: 
com/mycompany/bar/&#42;
+     * To exclude all routes form a specific package and its sub-packages use 
double wildcards: com/mycompany/bar/&#42;&#42;
+     * And to exclude all routes from two specific packages use: 
com/mycompany/bar/&#42;,com/mycompany/stuff/&#42;
+     */
+    private String javaRoutesExcludePattern;
+
+    /**
+     * Directory to scan for adding additional XML routes.
+     * You can turn this off by setting the value to false.
+     *
+     * Files can be loaded from either classpath or file by prefixing with 
classpath: or file:
+     * Wildcards is supported using a ANT pattern style paths, such as 
classpath:&#42;&#42;/&#42;camel&#42;.xml
+     *
+     * Multiple directories can be specified and separated by comma, such as:
+     * file:/myapp/mycamel/&#42;.xml,file:/myapp/myothercamel/&#42;.xml
+     */
+    private String xmlRoutes = "classpath:camel/*.xml";
+
+    /**
+     * Directory to scan for adding additional XML rests.
+     * You can turn this off by setting the value to false.
+     *
+     * Files can be loaded from either classpath or file by prefixing with 
classpath: or file:
+     * Wildcards is supported using a ANT pattern style paths, such as 
classpath:&#42;&#42;/&#42;camel&#42;.xml
+     *
+     * Multiple directories can be specified and separated by comma, such as:
+     * file:/myapp/mycamel/&#42;.xml,file:/myapp/myothercamel/&#42;.xml
+     */
+    private String xmlRests = "classpath:camel-rest/*.xml";
 
     // Getters & setters
     // -----------------
@@ -485,35 +494,4 @@ public class CamelConfigurationProperties extends 
DefaultConfigurationProperties
         this.warnOnEarlyShutdown = warnOnEarlyShutdown;
     }
 
-    public String getJavaRoutesIncludePattern() {
-        return javaRoutesIncludePattern;
-    }
-
-    public void setJavaRoutesIncludePattern(String javaRoutesIncludePattern) {
-        this.javaRoutesIncludePattern = javaRoutesIncludePattern;
-    }
-
-    public String getJavaRoutesExcludePattern() {
-        return javaRoutesExcludePattern;
-    }
-
-    public void setJavaRoutesExcludePattern(String javaRoutesExcludePattern) {
-        this.javaRoutesExcludePattern = javaRoutesExcludePattern;
-    }
-
-    public String getXmlRoutes() {
-        return xmlRoutes;
-    }
-
-    public void setXmlRoutes(String xmlRoutes) {
-        this.xmlRoutes = xmlRoutes;
-    }
-
-    public String getXmlRests() {
-        return xmlRests;
-    }
-
-    public void setXmlRests(String xmlRests) {
-        this.xmlRests = xmlRests;
-    }
 }
diff --git 
a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/RoutesCollector.java
 
b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelSpringBootApplicationListener.java
similarity index 60%
rename from 
components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/RoutesCollector.java
rename to 
components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelSpringBootApplicationListener.java
index cb02311..107d749 100644
--- 
a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/RoutesCollector.java
+++ 
b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/CamelSpringBootApplicationListener.java
@@ -16,8 +16,6 @@
  */
 package org.apache.camel.spring.boot;
 
-import java.io.FileNotFoundException;
-import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -27,20 +25,15 @@ 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.model.Model;
-import org.apache.camel.model.ModelHelper;
-import org.apache.camel.model.RoutesDefinition;
-import org.apache.camel.model.rest.RestsDefinition;
+import org.apache.camel.main.RoutesCollector;
+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.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.context.ApplicationContext;
@@ -48,34 +41,37 @@ import org.springframework.context.ApplicationListener;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.core.Ordered;
-import org.springframework.core.io.Resource;
-import org.springframework.util.AntPathMatcher;
 
 /**
- * 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 RoutesCollector implements 
ApplicationListener<ContextRefreshedEvent>, Ordered {
+public class CamelSpringBootApplicationListener implements 
ApplicationListener<ContextRefreshedEvent>, Ordered {
 
     // Static collaborators
 
-    private static final Logger LOG = 
LoggerFactory.getLogger(RoutesCollector.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 RoutesCollector(ApplicationContext applicationContext, 
List<CamelContextConfiguration> camelContextConfigurations,
-                           CamelConfigurationProperties 
configurationProperties) {
+    public CamelSpringBootApplicationListener(ApplicationContext 
applicationContext, List<CamelContextConfiguration> camelContextConfigurations,
+                                              CamelConfigurationProperties 
configurationProperties,
+                                              RoutesCollector 
springBootRoutesCollector) {
         this.applicationContext = applicationContext;
         this.camelContextConfigurations = new 
ArrayList<>(camelContextConfigurations);
         this.configurationProperties = configurationProperties;
+        this.springBootRoutesCollector = springBootRoutesCollector;
     }
 
     // Overridden
@@ -89,97 +85,15 @@ public class RoutesCollector implements 
ApplicationListener<ContextRefreshedEven
                 && camelContext.getStatus().isStopped()) {
             LOG.debug("Post-processing CamelContext bean: {}", 
camelContext.getName());
 
-            final AntPathMatcher matcher = new AntPathMatcher();
-            final List<RoutesBuilder> routes = new ArrayList<>();
-            for (RoutesBuilder routesBuilder : 
applicationContext.getBeansOfType(RoutesBuilder.class, 
configurationProperties.isIncludeNonSingletons(), true).values()) {
-                // filter out abstract classes
-                boolean abs = 
Modifier.isAbstract(routesBuilder.getClass().getModifiers());
-                if (!abs) {
-                    String name = routesBuilder.getClass().getName();
-                    // make name as path so we can use ant path matcher
-                    name = name.replace('.', '/');
-
-                    String exclude = 
configurationProperties.getJavaRoutesExcludePattern();
-                    String include = 
configurationProperties.getJavaRoutesIncludePattern();
+            RoutesConfigurer configurer = new 
RoutesConfigurer(springBootRoutesCollector);
+            configurer.configureRoutes(camelContext, configurationProperties);
 
-                    boolean match = !"false".equals(include);
-                    // exclude take precedence over include
-                    if (match && ObjectHelper.isNotEmpty(exclude)) {
-                        // there may be multiple separated by comma
-                        String[] parts = exclude.split(",");
-                        for (String part : parts) {
-                            // must negate when excluding, and hence !
-                            match = !matcher.match(part, name);
-                            LOG.trace("Java RoutesBuilder: {} exclude filter: 
{} -> {}", name, part, match);
-                            if (!match) {
-                                break;
-                            }
-                        }
-                    }
-                    // special support for testing with @ExcludeRoutes 
annotation with camel-test-spring
-                    exclude = 
System.getProperty("CamelTestSpringExcludeRoutes");
-                    // exclude take precedence over include
-                    if (match && ObjectHelper.isNotEmpty(exclude)) {
-                        // 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('.', '/');
-                        // there may be multiple separated by comma
-                        String[] parts = exclude.split(",");
-                        for (String part : parts) {
-                            // must negate when excluding, and hence !
-                            match = !matcher.match(part, name);
-                            LOG.trace("Java RoutesBuilder: {} exclude filter: 
{} -> {}", name, part, match);
-                            if (!match) {
-                                break;
-                            }
-                        }
-                    }
-                    if (match && ObjectHelper.isNotEmpty(include)) {
-                        // there may be multiple separated by comma
-                        String[] parts = include.split(",");
-                        for (String part : parts) {
-                            match = matcher.match(part, name);
-                            LOG.trace("Java RoutesBuilder: {} include filter: 
{} -> {}", name, part, match);
-                            if (match) {
-                                break;
-                            }
-                        }
-                    }
-                    LOG.debug("Java RoutesBuilder: {} accepted by 
include/exclude filter: {}", name, match);
-                    if (match) {
-                        routes.add(routesBuilder);
-                    }
-                }
-            }
-
-            // 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) {
-                    loadXmlRoutes(applicationContext, camelContext, 
configurationProperties.getXmlRoutes());
-                }
-
-                boolean scanRests = 
!configurationProperties.getXmlRests().equals("false");
-                if (scanRests) {
-                    loadXmlRests(applicationContext, camelContext, 
configurationProperties.getXmlRests());
-                }
-
-                for (CamelContextConfiguration camelContextConfiguration : 
camelContextConfigurations) {
-                    LOG.debug("CamelContextConfiguration found. Invoking 
beforeApplicationStart: {}", camelContextConfiguration);
-                    
camelContextConfiguration.beforeApplicationStart(camelContext);
-                }
-
                 if (configurationProperties.isMainRunController()) {
                     CamelMainRunController controller = new 
CamelMainRunController(applicationContext, camelContext);
 
@@ -192,8 +106,8 @@ public class RoutesCollector implements 
ApplicationListener<ContextRefreshedEven
                         }
                         // 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);
@@ -202,7 +116,7 @@ public class RoutesCollector implements 
ApplicationListener<ContextRefreshedEven
                     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() {
@@ -241,8 +155,8 @@ public class RoutesCollector implements 
ApplicationListener<ContextRefreshedEven
 
                             // 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);
@@ -300,39 +214,6 @@ public class RoutesCollector implements 
ApplicationListener<ContextRefreshedEven
 
     // Helpers
 
-    private void loadXmlRoutes(ApplicationContext applicationContext, 
CamelContext camelContext, String directory) throws Exception {
-        String[] parts = directory.split(",");
-        for (String part : parts) {
-            LOG.info("Loading additional Camel XML routes from: {}", part);
-            try {
-                Resource[] xmlRoutes = applicationContext.getResources(part);
-                for (Resource xmlRoute : xmlRoutes) {
-                    LOG.debug("Found XML route: {}", xmlRoute);
-                    RoutesDefinition routes = 
ModelHelper.loadRoutesDefinition(camelContext, xmlRoute.getInputStream());
-                    
camelContext.getExtension(Model.class).addRouteDefinitions(routes.getRoutes());
-                }
-            } catch (FileNotFoundException e) {
-                LOG.debug("No XML routes found in {}. Skipping XML routes 
detection.", part);
-            }
-        }
-    }
-
-    private void loadXmlRests(ApplicationContext applicationContext, 
CamelContext camelContext, String directory) throws Exception {
-        String[] parts = directory.split(",");
-        for (String part : parts) {
-            LOG.info("Loading additional Camel XML rests from: {}", part);
-            try {
-                final Resource[] xmlRests = 
applicationContext.getResources(part);
-                for (final Resource xmlRest : xmlRests) {
-                    RestsDefinition rests = 
ModelHelper.loadRestsDefinition(camelContext, xmlRest.getInputStream());
-                    
camelContext.getExtension(Model.class).addRestDefinitions(rests.getRests(), 
true);
-                }
-            } catch (FileNotFoundException e) {
-                LOG.debug("No XML rests found in {}. Skipping XML rests 
detection.", part);
-            }
-        }
-    }
-
     private void terminateMainControllerAfter(final CamelContext camelContext, 
int seconds, final AtomicBoolean completed, final CountDownLatch latch) {
         ScheduledExecutorService executorService = 
camelContext.getExecutorServiceManager().newSingleThreadScheduledExecutor(this, 
"CamelSpringBootTerminateTask");
         Runnable task = () -> {
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
new file mode 100644
index 0000000..335a46c
--- /dev/null
+++ 
b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/SpringBootRoutesCollector.java
@@ -0,0 +1,160 @@
+/**
+ * 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.spring.boot;
+
+import java.io.FileNotFoundException;
+import java.lang.reflect.Modifier;
+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.DefaultRoutesCollector;
+import org.apache.camel.model.ModelHelper;
+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.springframework.context.ApplicationContext;
+import org.springframework.core.io.Resource;
+
+/**
+ * Spring Boot {@link org.apache.camel.main.RoutesCollector}.
+ */
+public class SpringBootRoutesCollector extends DefaultRoutesCollector {
+
+    private final ApplicationContext applicationContext;
+
+    public SpringBootRoutesCollector(ApplicationContext applicationContext) {
+        this.applicationContext = applicationContext;
+    }
+
+    @Override
+    public List<RoutesBuilder> collectRoutesFromRegistry(CamelContext 
camelContext, String excludePattern, String includePattern) {
+        final List<RoutesBuilder> routes = new ArrayList<>();
+
+        final AntPathMatcher matcher = new AntPathMatcher();
+        for (RoutesBuilder routesBuilder : 
applicationContext.getBeansOfType(RoutesBuilder.class, true, true).values()) {
+            // filter out abstract classes
+            boolean abs = 
Modifier.isAbstract(routesBuilder.getClass().getModifiers());
+            if (!abs) {
+                String name = routesBuilder.getClass().getName();
+                // make name as path so we can use ant path matcher
+                name = name.replace('.', '/');
+
+                boolean match = !"false".equals(includePattern);
+                // exclude take precedence over include
+                if (match && ObjectHelper.isNotEmpty(excludePattern)) {
+                    // there may be multiple separated by comma
+                    String[] parts = excludePattern.split(",");
+                    for (String part : parts) {
+                        // must negate when excluding, and hence !
+                        match = !matcher.match(part, name);
+                        log.trace("Java RoutesBuilder: {} exclude filter: {} 
-> {}", name, part, match);
+                        if (!match) {
+                            break;
+                        }
+                    }
+                }
+                // special support for testing with @ExcludeRoutes annotation 
with camel-test-spring
+                excludePattern = 
System.getProperty("CamelTestSpringExcludeRoutes");
+                // exclude take precedence over include
+                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
+                    excludePattern = excludePattern.replace('.', '/');
+                    // there may be multiple separated by comma
+                    String[] parts = excludePattern.split(",");
+                    for (String part : parts) {
+                        // must negate when excluding, and hence !
+                        match = !matcher.match(part, name);
+                        log.trace("Java RoutesBuilder: {} exclude filter: {} 
-> {}", name, part, match);
+                        if (!match) {
+                            break;
+                        }
+                    }
+                }
+                if (match && ObjectHelper.isNotEmpty(includePattern)) {
+                    // there may be multiple separated by comma
+                    String[] parts = includePattern.split(",");
+                    for (String part : parts) {
+                        match = matcher.match(part, name);
+                        log.trace("Java RoutesBuilder: {} include filter: {} 
-> {}", name, part, match);
+                        if (match) {
+                            break;
+                        }
+                    }
+                }
+                log.debug("Java RoutesBuilder: {} accepted by include/exclude 
filter: {}", name, match);
+                if (match) {
+                    routes.add(routesBuilder);
+                }
+            }
+        }
+
+        return routes;
+    }
+
+    @Override
+    public List<RoutesDefinition> collectXmlRoutesFromDirectory(CamelContext 
camelContext, String directory) {
+        List<RoutesDefinition> answer = new ArrayList<>();
+
+        String[] parts = directory.split(",");
+        for (String part : parts) {
+            log.info("Loading additional Camel XML routes from: {}", part);
+            try {
+                Resource[] xmlRoutes = applicationContext.getResources(part);
+                for (Resource xmlRoute : xmlRoutes) {
+                    log.debug("Found XML route: {}", xmlRoute);
+                    RoutesDefinition routes = 
ModelHelper.loadRoutesDefinition(camelContext, xmlRoute.getInputStream());
+                    answer.add(routes);
+                }
+            } catch (FileNotFoundException e) {
+                log.debug("No XML routes found in {}. Skipping XML routes 
detection.", part);
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
+            }
+        }
+
+        return answer;
+    }
+
+    @Override
+    public List<RestsDefinition> collectXmlRestsFromDirectory(CamelContext 
camelContext, String directory) {
+        List<RestsDefinition> answer = new ArrayList<>();
+
+        String[] parts = directory.split(",");
+        for (String part : parts) {
+            log.info("Loading additional Camel XML rests from: {}", part);
+            try {
+                final Resource[] xmlRests = 
applicationContext.getResources(part);
+                for (final Resource xmlRest : xmlRests) {
+                    RestsDefinition rests = 
ModelHelper.loadRestsDefinition(camelContext, xmlRest.getInputStream());
+                    answer.add(rests);
+                }
+            } catch (FileNotFoundException e) {
+                log.debug("No XML rests found in {}. Skipping XML rests 
detection.", part);
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
+            }
+        }
+
+        return answer;
+    }
+
+}
diff --git 
a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/SupervisingRouteControllerTest.java
 
b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/SupervisingRouteControllerTest.java
index 3b2b640..7d9c495 100644
--- 
a/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/SupervisingRouteControllerTest.java
+++ 
b/components/camel-spring-boot/src/test/java/org/apache/camel/spring/boot/SupervisingRouteControllerTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.spring.boot;
 
+import java.util.concurrent.TimeUnit;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.ServiceStatus;
 import org.apache.camel.builder.RouteBuilder;
@@ -32,6 +34,8 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.test.annotation.DirtiesContext;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import static org.awaitility.Awaitility.await;
+
 @DirtiesContext
 @RunWith(SpringRunner.class)
 @SpringBootTest(
@@ -42,6 +46,7 @@ import org.springframework.test.context.junit4.SpringRunner;
     },
     properties = {
         "camel.springboot.xml-routes = false",
+        "camel.springboot.xml-rests = false",
         "camel.springboot.main-run-controller = true",
         "camel.supervising.controller.enabled = true",
         "camel.supervising.controller.initial-delay = 2s",
@@ -78,13 +83,18 @@ public class SupervisingRouteControllerTest {
         Assert.assertEquals(Long.MAX_VALUE, bar.getMaxDelay().toMillis());
         Assert.assertEquals(3L, bar.getMaxAttempts().longValue());
 
-        Assert.assertEquals(controller, 
context.getRoute("foo").getRouteContext().getRouteController());
-        Assert.assertEquals(controller, 
context.getRoute("bar").getRouteContext().getRouteController());
-        
Assert.assertNull(context.getRoute("timer-unmanaged").getRouteContext().getRouteController());
-        
Assert.assertNull(context.getRoute("timer-no-autostartup").getRouteContext().getRouteController());
-
         Assert.assertEquals(ServiceStatus.Stopped, 
context.getRouteController().getRouteStatus("foo"));
         Assert.assertEquals(ServiceStatus.Stopped, 
context.getRouteController().getRouteStatus("bar"));
+        Assert.assertEquals(ServiceStatus.Stopped, 
context.getRouteController().getRouteStatus("timer-no-autostartup"));
+        Assert.assertEquals(ServiceStatus.Stopped, 
context.getRouteController().getRouteStatus("jetty"));
+
+        // Wait for the controller to start the routes also unmanaged
+        await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
+            Assert.assertEquals(ServiceStatus.Started, 
context.getRouteController().getRouteStatus("jetty"));
+            Assert.assertEquals(ServiceStatus.Started, 
context.getRouteController().getRouteStatus("timer-unmanaged"));
+        });
+        Assert.assertEquals(ServiceStatus.Started, 
context.getRouteController().getRouteStatus("jetty"));
+        Assert.assertEquals(ServiceStatus.Started, 
context.getRouteController().getRouteStatus("timer-unmanaged"));
     }
 
     // *************************************
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 141685d..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.RoutesCollector;
+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);
-        RoutesCollector collector = context.getBean(RoutesCollector.class);
+        CamelSpringBootApplicationListener collector = 
context.getBean(CamelSpringBootApplicationListener.class);
         collector.onApplicationEvent(refreshEvent); //no changes should happen 
here
     }
 
diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/RouteContext.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/RouteContext.java
index feb117f..7c5b337 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/RouteContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/RouteContext.java
@@ -28,7 +28,6 @@ import org.apache.camel.NamedNode;
 import org.apache.camel.Processor;
 import org.apache.camel.Route;
 import org.apache.camel.RuntimeConfiguration;
-import org.apache.camel.meta.Experimental;
 
 /**
  * The context used to activate new routing rules
@@ -234,19 +233,14 @@ public interface RouteContext extends 
RuntimeConfiguration, EndpointAware {
      *
      * @return the route controller,
      */
-    @Experimental
-    default RouteController getRouteController() {
-        return null;
-    }
+    RouteController getRouteController();
 
     /**
      * Sets the {@link RouteController} for this route.
      *
      * @param controller the RouteController
      */
-    @Experimental
-    default void setRouteController(RouteController controller) {
-    }
+    void setRouteController(RouteController controller);
 
     Processor getOnCompletion(String onCompletionId);
 
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java 
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index ad8caf5..ee06fdd 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -28,6 +28,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Properties;
+import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -51,7 +52,6 @@ import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.PropertyConfigurer;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.support.LifecycleStrategySupport;
-import org.apache.camel.support.OrderedComparator;
 import org.apache.camel.support.PropertyBindingSupport;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
@@ -81,6 +81,7 @@ public abstract class BaseMainSupport extends ServiceSupport {
 
     protected final List<MainListener> listeners = new ArrayList<>();
     protected final MainConfigurationProperties mainConfigurationProperties = 
new MainConfigurationProperties();
+    protected RoutesCollector routesCollector = new DefaultRoutesCollector();
     protected List<RoutesBuilder> routeBuilders = new ArrayList<>();
     protected String routeBuilderClasses;
     protected List<Object> configurations = new ArrayList<>();
@@ -210,6 +211,17 @@ public abstract class BaseMainSupport extends 
ServiceSupport {
         configurations.add(configuration);
     }
 
+    public RoutesCollector getRoutesCollector() {
+        return routesCollector;
+    }
+
+    /**
+     * To use a custom {@link RoutesCollector}.
+     */
+    public void setRoutesCollector(RoutesCollector routesCollector) {
+        this.routesCollector = routesCollector;
+    }
+
     public String getRouteBuilderClasses() {
         return routeBuilderClasses;
     }
@@ -412,6 +424,19 @@ public abstract class BaseMainSupport extends 
ServiceSupport {
                 }
             }
         }
+
+        if (mainConfigurationProperties.getPackageScanRouteBuilders() != null) 
{
+            String[] pkgs = 
mainConfigurationProperties.getPackageScanRouteBuilders().split(",");
+            Set<Class<?>> set = 
camelContext.getExtension(ExtendedCamelContext.class).getPackageScanClassResolver().findImplementations(RoutesBuilder.class,
 pkgs);
+            for (Class<?> routeClazz : set) {
+                Object builder = 
camelContext.getInjector().newInstance(routeClazz);
+                if (builder instanceof RouteBuilder) {
+                    getRoutesBuilders().add((RouteBuilder) builder);
+                } else {
+                    LOG.warn("Class {} is not a RouteBuilder class", 
routeClazz);
+                }
+            }
+        }
     }
 
     protected void loadConfigurations(CamelContext camelContext) throws 
Exception {
@@ -519,11 +544,9 @@ public abstract class BaseMainSupport extends 
ServiceSupport {
 
         // try to load the route builders
         loadRouteBuilders(camelContext);
-        // sort routes according to ordered
-        routeBuilders.sort(OrderedComparator.get());
-        for (RoutesBuilder routeBuilder : routeBuilders) {
-            camelContext.addRoutes(routeBuilder);
-        }
+        // then configure and add the routes
+        RoutesConfigurer configurer = new RoutesConfigurer(routesCollector, 
routeBuilders);
+        configurer.configureRoutes(camelContext, mainConfigurationProperties);
         // register lifecycle so we are notified in Camel is stopped from JMX 
or somewhere else
         camelContext.addLifecycleStrategy(new MainLifecycleStrategy(completed, 
latch));
         // allow to do configuration before its started
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 3e92f77..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,11 @@ 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";
+    private String xmlRests = "classpath:camel-rest/*.xml";
 
     // getter and setters
     // --------------------------------------------------------------
@@ -704,6 +709,96 @@ 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;
+    }
+
+    /**
+     * 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.
+     *
+     * Multiple patterns can be specified separated by comma.
+     * For example to include all classes starting with Foo use: 
&#42;&#42;/Foo*
+     * To include all routes form a specific package use: 
com/mycompany/foo/&#42;
+     * To include all routes form a specific package and its sub-packages use 
double wildcards: com/mycompany/foo/&#42;&#42;
+     * And to include all routes from two specific packages use: 
com/mycompany/foo/&#42;,com/mycompany/stuff/&#42;
+     */
+    public void setJavaRoutesIncludePattern(String javaRoutesIncludePattern) {
+        this.javaRoutesIncludePattern = javaRoutesIncludePattern;
+    }
+
+    public String getJavaRoutesExcludePattern() {
+        return javaRoutesExcludePattern;
+    }
+
+    /**
+     * Used for exclusive 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.
+     * Multiple patterns can be specified separated by comma.
+     *
+     * For example to exclude all classes starting with Bar use: 
&#42;&#42;/Bar&#42;
+     * To exclude all routes form a specific package use: 
com/mycompany/bar/&#42;
+     * To exclude all routes form a specific package and its sub-packages use 
double wildcards: com/mycompany/bar/&#42;&#42;
+     * And to exclude all routes from two specific packages use: 
com/mycompany/bar/&#42;,com/mycompany/stuff/&#42;
+     */
+    public void setJavaRoutesExcludePattern(String javaRoutesExcludePattern) {
+        this.javaRoutesExcludePattern = javaRoutesExcludePattern;
+    }
+
+    public String getXmlRoutes() {
+        return xmlRoutes;
+    }
+
+    /**
+     * Directory to scan for adding additional XML routes.
+     * You can turn this off by setting the value to false.
+     *
+     * Files can be loaded from either classpath or file by prefixing with 
classpath: or file:
+     * Wildcards is supported using a ANT pattern style paths, such as 
classpath:&#42;&#42;/&#42;camel&#42;.xml
+     *
+     * Multiple directories can be specified and separated by comma, such as:
+     * file:/myapp/mycamel/&#42;.xml,file:/myapp/myothercamel/&#42;.xml
+     */
+    public void setXmlRoutes(String xmlRoutes) {
+        this.xmlRoutes = xmlRoutes;
+    }
+
+    public String getXmlRests() {
+        return xmlRests;
+    }
+
+    /**
+     * Directory to scan for adding additional XML rests.
+     * You can turn this off by setting the value to false.
+     *
+     * Files can be loaded from either classpath or file by prefixing with 
classpath: or file:
+     * Wildcards is supported using a ANT pattern style paths, such as 
classpath:&#42;&#42;/&#42;camel&#42;.xml
+     *
+     * Multiple directories can be specified and separated by comma, such as:
+     * file:/myapp/mycamel/&#42;.xml,file:/myapp/myothercamel/&#42;.xml
+     */
+    public void setXmlRests(String xmlRests) {
+        this.xmlRests = xmlRests;
+    }
+
     // fluent builders
     // --------------------------------------------------------------
 
@@ -1168,4 +1263,108 @@ public abstract class DefaultConfigurationProperties<T> 
{
         return (T) this;
     }
 
+    /**
+     * Tracing pattern to match which node EIPs to trace.
+     * For example to match all To EIP nodes, use to*.
+     * The pattern matches by node and route id's
+     * Multiple patterns can be separated by comma.
+     */
+    public T withTracingPattern(String tracingPattern) {
+        this.tracingPattern = tracingPattern;
+        return (T) this;
+    }
+
+    /**
+     * Sets the pattern used for determine which custom MDC keys to propagate 
during message routing when
+     * the routing engine continues routing asynchronously for the given 
message. Setting this pattern to * will
+     * propagate all custom keys. Or setting the pattern to foo*,bar* will 
propagate any keys starting with
+     * either foo or bar.
+     * Notice that a set of standard Camel MDC keys are always propagated 
which starts with camel. as key name.
+     *
+     * The match rules are applied in this order (case insensitive):
+     *
+     * 1. exact match, returns true
+     * 2. wildcard match (pattern ends with a * and the name starts with the 
pattern), returns true
+     * 3. regular expression match, returns true
+     * 4. otherwise returns false
+     */
+    public T withMdcLoggingKeysPattern(String mdcLoggingKeysPattern) {
+        this.mdcLoggingKeysPattern = mdcLoggingKeysPattern;
+        return (T) this;
+    }
+
+    /**
+     * 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.
+     *
+     * Multiple patterns can be specified separated by comma.
+     * For example to include all classes starting with Foo use: 
&#42;&#42;/Foo*
+     * To include all routes form a specific package use: 
com/mycompany/foo/&#42;
+     * To include all routes form a specific package and its sub-packages use 
double wildcards: com/mycompany/foo/&#42;&#42;
+     * And to include all routes from two specific packages use: 
com/mycompany/foo/&#42;,com/mycompany/stuff/&#42;
+     */
+    public T withJavaRoutesIncludePattern(String javaRoutesIncludePattern) {
+        this.javaRoutesIncludePattern = javaRoutesIncludePattern;
+        return (T) this;
+    }
+
+    /**
+     * Used for exclusive 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.
+     * Multiple patterns can be specified separated by comma.
+     *
+     * For example to exclude all classes starting with Bar use: 
&#42;&#42;/Bar&#42;
+     * To exclude all routes form a specific package use: 
com/mycompany/bar/&#42;
+     * To exclude all routes form a specific package and its sub-packages use 
double wildcards: com/mycompany/bar/&#42;&#42;
+     * And to exclude all routes from two specific packages use: 
com/mycompany/bar/&#42;,com/mycompany/stuff/&#42;
+     */
+    public T withJavaRoutesExcludePattern(String javaRoutesExcludePattern) {
+        this.javaRoutesExcludePattern = javaRoutesExcludePattern;
+        return (T) this;
+    }
+
+    /**
+     * Directory to scan for adding additional XML routes.
+     * You can turn this off by setting the value to false.
+     *
+     * Files can be loaded from either classpath or file by prefixing with 
classpath: or file:
+     * Wildcards is supported using a ANT pattern style paths, such as 
classpath:&#42;&#42;/&#42;camel&#42;.xml
+     *
+     * Multiple directories can be specified and separated by comma, such as:
+     * file:/myapp/mycamel/&#42;.xml,file:/myapp/myothercamel/&#42;.xml
+     */
+    public T withXmlRoutes(String xmlRoutes) {
+        this.xmlRoutes = xmlRoutes;
+        return (T) this;
+    }
+
+    /**
+     * Directory to scan for adding additional XML rests.
+     * You can turn this off by setting the value to false.
+     *
+     * Files can be loaded from either classpath or file by prefixing with 
classpath: or file:
+     * Wildcards is supported using a ANT pattern style paths, such as 
classpath:&#42;&#42;/&#42;camel&#42;.xml
+     *
+     * Multiple directories can be specified and separated by comma, such as:
+     * file:/myapp/mycamel/&#42;.xml,file:/myapp/myothercamel/&#42;.xml
+     */
+    public T withXmlRests(String xmlRests) {
+        this.xmlRests = xmlRests;
+        return (T) this;
+    }
 }
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/DefaultRoutesCollector.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultRoutesCollector.java
new file mode 100644
index 0000000..3bd10a3
--- /dev/null
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/DefaultRoutesCollector.java
@@ -0,0 +1,139 @@
+/*
+ * 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.main;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.model.ModelHelper;
+import org.apache.camel.model.RoutesDefinition;
+import org.apache.camel.model.rest.RestsDefinition;
+import org.apache.camel.support.ResourceHelper;
+import org.apache.camel.util.AntPathMatcher;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A default {@link RoutesCollector}.
+ */
+public class DefaultRoutesCollector implements RoutesCollector {
+
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Override
+    public List<RoutesBuilder> collectRoutesFromRegistry(CamelContext 
camelContext,
+                                                         String 
excludePattern, String includePattern) {
+        final List<RoutesBuilder> routes = new ArrayList<>();
+
+        final AntPathMatcher matcher = new AntPathMatcher();
+        Set<RoutesBuilder> builders = 
camelContext.getRegistry().findByType(RoutesBuilder.class);
+        for (RoutesBuilder routesBuilder : builders) {
+            // filter out abstract classes
+            boolean abs = 
Modifier.isAbstract(routesBuilder.getClass().getModifiers());
+            if (!abs) {
+                String name = routesBuilder.getClass().getName();
+                // make name as path so we can use ant path matcher
+                name = name.replace('.', '/');
+
+                boolean match = !"false".equals(includePattern);
+                // exclude take precedence over include
+                if (match && ObjectHelper.isNotEmpty(excludePattern)) {
+                    // there may be multiple separated by comma
+                    String[] parts = excludePattern.split(",");
+                    for (String part : parts) {
+                        // must negate when excluding, and hence !
+                        match = !matcher.match(part, name);
+                        log.trace("Java RoutesBuilder: {} exclude filter: {} 
-> {}", name, part, match);
+                        if (!match) {
+                            break;
+                        }
+                    }
+                }
+                if (match && ObjectHelper.isNotEmpty(includePattern)) {
+                    // there may be multiple separated by comma
+                    String[] parts = includePattern.split(",");
+                    for (String part : parts) {
+                        match = matcher.match(part, name);
+                        log.trace("Java RoutesBuilder: {} include filter: {} 
-> {}", name, part, match);
+                        if (match) {
+                            break;
+                        }
+                    }
+                }
+                log.debug("Java RoutesBuilder: {} accepted by include/exclude 
filter: {}", name, match);
+                if (match) {
+                    routes.add(routesBuilder);
+                }
+            }
+        }
+
+        return routes;
+    }
+
+    @Override
+    public List<RoutesDefinition> collectXmlRoutesFromDirectory(CamelContext 
camelContext, String directory) {
+        List<RoutesDefinition> answer = new ArrayList<>();
+
+        String[] parts = directory.split(",");
+        for (String part : parts) {
+            log.info("Loading additional Camel XML routes from: {}", part);
+            try {
+                InputStream is = 
ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, part);
+                log.debug("Found XML route: {}", is);
+                RoutesDefinition routes = 
ModelHelper.loadRoutesDefinition(camelContext, is);
+                answer.add(routes);
+            } catch (FileNotFoundException e) {
+                log.debug("No XML routes found in {}. Skipping XML routes 
detection.", part);
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
+            }
+        }
+
+        return answer;
+    }
+
+    @Override
+    public List<RestsDefinition> collectXmlRestsFromDirectory(CamelContext 
camelContext, String directory) {
+        List<RestsDefinition> answer = new ArrayList<>();
+
+        String[] parts = directory.split(",");
+        for (String part : parts) {
+            log.info("Loading additional Camel XML rests from: {}", part);
+            try {
+                InputStream is = 
ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, part);
+                log.debug("Found XML rest: {}", is);
+                RestsDefinition rests = 
ModelHelper.loadRestsDefinition(camelContext, is);
+                answer.add(rests);
+            } catch (FileNotFoundException e) {
+                log.debug("No XML rests found in {}. Skipping XML rests 
detection.", part);
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
+            }
+        }
+
+        return answer;
+    }
+
+}
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
index ffdca5d..28ab76d 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/MainConfigurationProperties.java
@@ -30,6 +30,7 @@ public class MainConfigurationProperties extends 
DefaultConfigurationProperties<
     private boolean autowireComponentPropertiesAllowPrivateSetter = true;
     private int durationHitExitCode;
     private boolean hangupInterceptorEnabled = true;
+    private String packageScanRouteBuilders;
 
     // extended configuration
     private final HystrixConfigurationProperties 
hystrixConfigurationProperties = new HystrixConfigurationProperties(this);
@@ -178,6 +179,19 @@ public class MainConfigurationProperties extends 
DefaultConfigurationProperties<
         this.hangupInterceptorEnabled = hangupInterceptorEnabled;
     }
 
+    public String getPackageScanRouteBuilders() {
+        return packageScanRouteBuilders;
+    }
+
+    /**
+     * Sets package names for scanning for {@link 
org.apache.camel.builder.RouteBuilder} classes as candidates to be included.
+     * If you are using Spring Boot then its instead recommended to use Spring 
Boots component scanning and annotate your route builder
+     * classes with `@Component`. In other words only use this for Camel Main 
in standalone mode.
+     */
+    public void setPackageScanRouteBuilders(String packageScanRouteBuilders) {
+        this.packageScanRouteBuilders = packageScanRouteBuilders;
+    }
+
     public int getDurationHitExitCode() {
         return durationHitExitCode;
     }
@@ -301,4 +315,14 @@ public class MainConfigurationProperties extends 
DefaultConfigurationProperties<
         return this;
     }
 
+    /**
+     * Sets package names for scanning for {@link 
org.apache.camel.builder.RouteBuilder} classes as candidates to be included.
+     * If you are using Spring Boot then its instead recommended to use Spring 
Boots component scanning and annotate your route builder
+     * classes with `@Component`. In other words only use this for Camel Main 
in standalone mode.
+     */
+    public MainConfigurationProperties withPackageScanRouteBuilders(String 
packageScanRouteBuilders) {
+        this.packageScanRouteBuilders = packageScanRouteBuilders;
+        return this;
+    }
+
 }
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
new file mode 100644
index 0000000..8d8b2fc
--- /dev/null
+++ b/core/camel-main/src/main/java/org/apache/camel/main/RoutesCollector.java
@@ -0,0 +1,61 @@
+/*
+ * 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.main;
+
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+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 adds these into the Camel context.
+ */
+public interface RoutesCollector {
+
+    /**
+     * 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..589988e
--- /dev/null
+++ b/core/camel-main/src/main/java/org/apache/camel/main/RoutesConfigurer.java
@@ -0,0 +1,109 @@
+/**
+ * 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.ArrayList;
+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;
+    private final List<RoutesBuilder> routesBuilders;
+
+    /**
+     * Creates a new routes configurer
+     *
+     * @param routesCollector  routes collector
+     */
+    public RoutesConfigurer(RoutesCollector routesCollector) {
+        this(routesCollector, new ArrayList<>());
+    }
+
+    /**
+     * Creates a new routes configurer
+     *
+     * @param routesCollector  routes collector
+     * @param routesBuilders   existing route builders
+     */
+    public RoutesConfigurer(RoutesCollector routesCollector, 
List<RoutesBuilder> routesBuilders) {
+        this.routesCollector = routesCollector;
+        this.routesBuilders = routesBuilders;
+    }
+
+    /**
+     * Collects routes and rests from the various sources (like registry or 
opinionated
+     * classpath locations) and injects (adds) 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());
+
+                // add newly discovered routes
+                routesBuilders.addAll(routes);
+                // sort routes according to ordered
+                routesBuilders.sort(OrderedComparator.get());
+                // then add the routes
+                for (RoutesBuilder builder : routesBuilders) {
+                    LOG.debug("Adding routes into CamelContext from 
RoutesBuilder: {}", builder);
+                    camelContext.addRoutes(builder);
+                }
+
+                boolean scan = !config.getXmlRoutes().equals("false");
+                if (scan) {
+                    List<RoutesDefinition> defs = 
routesCollector.collectXmlRoutesFromDirectory(camelContext, 
config.getXmlRoutes());
+                    for (RoutesDefinition def : defs) {
+                        LOG.debug("Adding routes into CamelContext from XML 
files: {}", config.getXmlRoutes());
+                        
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) {
+                        LOG.debug("Adding rests into CamelContext from XML 
files: {}", config.getXmlRests());
+                        
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 8548426..bd3d045 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
@@ -147,6 +147,18 @@
                        "defaultValue":"true"
                },
                {
+                       "name":"camel.main.java-routes-exclude-pattern",
+                       "type":"java.lang.String",
+                       
"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
+                       "description":"Used for exclusive 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. Multiple patterns can be specified separated by comma. 
For example to exclude all classes starting with Bar use: &#42;&#42;\/Bar&#42; 
To exclude all routes form a specific package use: com\/mycompany\/bar\/&#42; 
To exclude all routes form a specific package and i [...]
+               },
+               {
+                       "name":"camel.main.java-routes-include-pattern",
+                       "type":"java.lang.String",
+                       
"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
+                       "description":"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. Multiple patterns can be specified separated by comma. 
For example to include all classes starting with Foo use: &#42;&#42;\/Foo To 
include all routes form a specific package use: com\/mycompany\/foo\/&#42; To 
include all routes form a specific package and its su [...]
+               },
+               {
                        "name":"camel.main.jmx-create-connector",
                        "type":"boolean",
                        
"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -218,6 +230,12 @@
                        "description":"Sets the name of the CamelContext."
                },
                {
+                       "name":"camel.main.package-scan-route-builders",
+                       "type":"java.lang.String",
+                       
"sourceType":"org.apache.camel.main.MainConfigurationProperties",
+                       "description":"Sets package names for scanning for 
org.apache.camel.builder.RouteBuilder classes as candidates to be included. If 
you are using Spring Boot then its instead recommended to use Spring Boots 
component scanning and annotate your route builder classes with Component. In 
other words only use this for Camel Main in standalone mode."
+               },
+               {
                        "name":"camel.main.producer-template-cache-size",
                        "type":"int",
                        
"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
@@ -237,6 +255,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",
@@ -368,6 +393,20 @@
                        "description":"To turn on MDC logging"
                },
                {
+                       "name":"camel.main.xml-rests",
+                       "type":"java.lang.String",
+                       
"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
+                       "description":"Directory to scan for adding additional 
XML rests. You can turn this off by setting the value to false. Files can be 
loaded from either classpath or file by prefixing with classpath: or file: 
Wildcards is supported using a ANT pattern style paths, such as 
classpath:&#42;&#42;\/&#42;camel&#42;.xml Multiple directories can be specified 
and separated by comma, such as: 
file:\/myapp\/mycamel\/&#42;.xml,file:\/myapp\/myothercamel\/&#42;.xml",
+                       "defaultValue":"classpath:camel-rest\/*.xml"
+               },
+               {
+                       "name":"camel.main.xml-routes",
+                       "type":"java.lang.String",
+                       
"sourceType":"org.apache.camel.main.DefaultConfigurationProperties",
+                       "description":"Directory to scan for adding additional 
XML routes. You can turn this off by setting the value to false. Files can be 
loaded from either classpath or file by prefixing with classpath: or file: 
Wildcards is supported using a ANT pattern style paths, such as 
classpath:&#42;&#42;\/&#42;camel&#42;.xml Multiple directories can be specified 
and separated by comma, such as: 
file:\/myapp\/mycamel\/&#42;.xml,file:\/myapp\/myothercamel\/&#42;.xml",
+                       "defaultValue":"classpath:camel\/*.xml"
+               },
+               {
                        
"name":"camel.hystrix.allow-maximum-size-to-diverge-from-core-size",
                        "type":"java.lang.Boolean",
                        
"sourceType":"org.apache.camel.main.HystrixConfigurationProperties",
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/MainRoutesCollectorPackageScanTest.java
 
b/core/camel-main/src/test/java/org/apache/camel/main/MainRoutesCollectorPackageScanTest.java
new file mode 100644
index 0000000..06a4b1d
--- /dev/null
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/MainRoutesCollectorPackageScanTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.main;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MainRoutesCollectorPackageScanTest extends Assert {
+
+    @Test
+    public void testMainRoutesCollector() throws Exception {
+        Main main = new Main();
+        
main.configure().withPackageScanRouteBuilders("org.apache.camel.main.scan");
+        main.start();
+
+        CamelContext camelContext = main.getCamelContext();
+        assertNotNull(camelContext);
+        assertEquals(2, camelContext.getRoutes().size());
+
+        MockEndpoint endpoint = camelContext.getEndpoint("mock:scan", 
MockEndpoint.class);
+        endpoint.expectedBodiesReceived("Hello World");
+        MockEndpoint endpoint2 = camelContext.getEndpoint("mock:dummy", 
MockEndpoint.class);
+        endpoint2.expectedBodiesReceived("Bye World");
+
+        main.getCamelTemplate().sendBody("direct:scan", "Hello World");
+        main.getCamelTemplate().sendBody("direct:dummy", "Bye World");
+
+        endpoint.assertIsSatisfied();
+        endpoint2.assertIsSatisfied();
+
+        main.stop();
+    }
+
+}
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/MainRoutesCollectorTest.java
 
b/core/camel-main/src/test/java/org/apache/camel/main/MainRoutesCollectorTest.java
new file mode 100644
index 0000000..56ab2ec
--- /dev/null
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/MainRoutesCollectorTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.main;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MainRoutesCollectorTest extends Assert {
+
+    @Test
+    public void testMainRoutesCollector() throws Exception {
+        Main main = new Main();
+        main.bind("myBarRoute", new MyRouteBuilder());
+        main.start();
+
+        CamelContext camelContext = main.getCamelContext();
+        assertNotNull(camelContext);
+        assertEquals(1, camelContext.getRoutes().size());
+
+        MockEndpoint endpoint = camelContext.getEndpoint("mock:results", 
MockEndpoint.class);
+        endpoint.expectedBodiesReceived("Hello World");
+
+        main.getCamelTemplate().sendBody("direct:start", "Hello World");
+
+        endpoint.assertIsSatisfied();
+
+        main.stop();
+    }
+
+    public static class MyRouteBuilder extends RouteBuilder {
+
+        @Override
+        public void configure() throws Exception {
+            from("direct:start").to("mock:results");
+        }
+    }
+}
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/scan/MyDummyRouteBuilder.java
 
b/core/camel-main/src/test/java/org/apache/camel/main/scan/MyDummyRouteBuilder.java
new file mode 100644
index 0000000..d2a5d78
--- /dev/null
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/scan/MyDummyRouteBuilder.java
@@ -0,0 +1,27 @@
+/**
+ * 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.scan;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class MyDummyRouteBuilder extends RouteBuilder {
+
+    @Override
+    public void configure() throws Exception {
+        from("direct:dummy").to("mock:dummy");
+    }
+}
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/scan/MyScanRouteBuilder.java
 
b/core/camel-main/src/test/java/org/apache/camel/main/scan/MyScanRouteBuilder.java
new file mode 100644
index 0000000..ff258c7
--- /dev/null
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/scan/MyScanRouteBuilder.java
@@ -0,0 +1,27 @@
+/**
+ * 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.scan;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class MyScanRouteBuilder extends RouteBuilder {
+
+    @Override
+    public void configure() throws Exception {
+        from("direct:scan").to("mock:scan");
+    }
+}

Reply via email to