diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java
index 9f6a2cd0b3..20052873c6 100644
--- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/SpringBootApplication.java
@@ -24,9 +24,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.SpringBootConfiguration;
+import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
/**
@@ -46,7 +49,7 @@ import org.springframework.core.annotation.AliasFor;
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
-@ComponentScan
+@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {
/**
diff --git a/spring-boot/src/main/java/org/springframework/boot/context/TypeExcludeFilter.java b/spring-boot/src/main/java/org/springframework/boot/context/TypeExcludeFilter.java
new file mode 100644
index 0000000000..a1b2ecac0d
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/context/TypeExcludeFilter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed 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.springframework.boot.context;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.core.type.filter.TypeFilter;
+
+/**
+ * Provides exclusion {@link TypeFilter TypeFilters} that are loaded from the
+ * {@link BeanFactory} and automatically applied to {@code SpringBootApplication}
+ * scanning. Can also be used directly with {@code @ComponentScan} as follows:
+ *
+ * @ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
+ *
+ *
+ * Implementations should provide a subclass registered with {@link BeanFactory} and
+ * override the {@link #match(MetadataReader, MetadataReaderFactory)} method.
+ *
+ * Note that {@code TypeExcludeFilters} are initialized very early in the application
+ * lifecyle, they should generally not have dependencies on any other beans. They and are
+ * primarily used internally to support {@code spring-boot-test}.
+ *
+ * @author Phillip Webb
+ * @since 1.4.0
+ */
+public class TypeExcludeFilter implements TypeFilter, BeanFactoryAware {
+
+ private BeanFactory beanFactory;
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ public boolean match(MetadataReader metadataReader,
+ MetadataReaderFactory metadataReaderFactory) throws IOException {
+ if (this.beanFactory instanceof ListableBeanFactory
+ && getClass().equals(TypeExcludeFilter.class)) {
+ Collection delegates = ((ListableBeanFactory) this.beanFactory)
+ .getBeansOfType(TypeExcludeFilter.class).values();
+ for (TypeExcludeFilter delegate : delegates) {
+ if (delegate.match(metadataReader, metadataReaderFactory)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/context/TypeExcludeFilterTests.java b/spring-boot/src/test/java/org/springframework/boot/context/TypeExcludeFilterTests.java
new file mode 100644
index 0000000000..abb82ecbbb
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/context/TypeExcludeFilterTests.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed 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.springframework.boot.context;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.boot.context.filtersample.ExampleComponent;
+import org.springframework.boot.context.filtersample.ExampleFilteredComponent;
+import org.springframework.boot.context.filtersample.SampleTypeExcludeFilter;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.FilterType;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link TypeExcludeFilter}.
+ *
+ * @author Phillip Webb
+ */
+public class TypeExcludeFilterTests {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void loadsTypeExcludeFilters() throws Exception {
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ context.getBeanFactory().registerSingleton("filter1",
+ new WithoutMatchOverrideFilter());
+ context.getBeanFactory().registerSingleton("filter2",
+ new SampleTypeExcludeFilter());
+ context.register(Config.class);
+ context.refresh();
+ assertThat(context.getBean(ExampleComponent.class)).isNotNull();
+ this.thrown.expect(NoSuchBeanDefinitionException.class);
+ context.getBean(ExampleFilteredComponent.class);
+ context.close();
+ }
+
+ @Configuration
+ @ComponentScan(basePackageClasses = SampleTypeExcludeFilter.class, excludeFilters = @Filter(type = FilterType.CUSTOM, classes = SampleTypeExcludeFilter.class))
+ static class Config {
+
+ }
+
+ static class WithoutMatchOverrideFilter extends TypeExcludeFilter {
+
+ }
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/context/filtersample/ExampleComponent.java b/spring-boot/src/test/java/org/springframework/boot/context/filtersample/ExampleComponent.java
new file mode 100644
index 0000000000..94640d0811
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/context/filtersample/ExampleComponent.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed 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.springframework.boot.context.filtersample;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class ExampleComponent {
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/context/filtersample/ExampleFilteredComponent.java b/spring-boot/src/test/java/org/springframework/boot/context/filtersample/ExampleFilteredComponent.java
new file mode 100644
index 0000000000..e41338c931
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/context/filtersample/ExampleFilteredComponent.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed 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.springframework.boot.context.filtersample;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class ExampleFilteredComponent {
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/context/filtersample/SampleTypeExcludeFilter.java b/spring-boot/src/test/java/org/springframework/boot/context/filtersample/SampleTypeExcludeFilter.java
new file mode 100644
index 0000000000..87ffabdf82
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/context/filtersample/SampleTypeExcludeFilter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2012-2016 the original author or authors.
+ *
+ * Licensed 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.springframework.boot.context.filtersample;
+
+import java.io.IOException;
+
+import org.springframework.boot.context.TypeExcludeFilter;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+
+public class SampleTypeExcludeFilter extends TypeExcludeFilter {
+
+ @Override
+ public boolean match(MetadataReader metadataReader,
+ MetadataReaderFactory metadataReaderFactory) throws IOException {
+ return metadataReader.getClassMetadata().getClassName()
+ .equals(ExampleFilteredComponent.class.getName());
+ }
+
+}