105

Is there a simple way to exclude a package / sub-package from autowiring in Spring 3.1?

E.g., if I wanted to include a component scan with a base package of com.example is there a simple way to exclude com.example.ignore?

(Why? I'd like to exclude some components from my integration tests)

richarbernal
  • 1,063
  • 2
  • 14
  • 32
HolySamosa
  • 9,011
  • 14
  • 69
  • 102

10 Answers10

97

I'm not sure you can exclude packages explicitly with an <exclude-filter>, but I bet using a regex filter would effectively get you there:

 <context:component-scan base-package="com.example">
    <context:exclude-filter type="regex" expression="com\.example\.ignore\..*"/>
 </context:component-scan>

To make it annotation-based, you'd annotate each class you wanted excluded for integration tests with something like @com.example.annotation.ExcludedFromITests. Then the component-scan would look like:

 <context:component-scan base-package="com.example">
    <context:exclude-filter type="annotation" expression="com.example.annotation.ExcludedFromITests"/>
 </context:component-scan>

That's clearer because now you've documented in the source code itself that the class is not intended to be included in an application context for integration tests.

Jonathan W
  • 3,759
  • 19
  • 20
65

I am using @ComponentScan as follows for the same use case. This is the same as BenSchro10's XML answer but this uses annotations. Both use a filter with type=AspectJ

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan(basePackages = { "com.example" },
    excludeFilters = @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "com.example.ignore.*"))
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
Community
  • 1
  • 1
Kirby
  • 15,127
  • 10
  • 89
  • 104
49

For Spring 4 I use the following
(I am posting it as the question is 4 years old and more people use Spring 4 than Spring 3.1):

@Configuration
@ComponentScan(basePackages = "com.example", 
  excludeFilters = @Filter(type=FilterType.REGEX,pattern="com\\.example\\.ignore\\..*")) 
public class RootConfig {
    // ...
}
Witold Kaczurba
  • 9,845
  • 3
  • 58
  • 67
19

It seems you've done this through XML, but if you were working in new Spring best practice, your config would be in Java, and you could exclude them as so:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "net.example.tool",
  excludeFilters = {@ComponentScan.Filter(
    type = FilterType.ASSIGNABLE_TYPE,
    value = {JPAConfiguration.class, SecurityConfig.class})
  })
Arsalan Khalid
  • 246
  • 1
  • 4
  • 15
  • 10
    @JonathanW But nevertheless, a really useful answer for people coming to this page from a google search – Stewart Jun 28 '17 at 16:34
12

This works in Spring 3.0.5. So, I would think it would work in 3.1

<context:component-scan base-package="com.example">  
    <context:exclude-filter type="aspectj" expression="com.example.dontscanme.*" />  
</context:component-scan> 
Kirby
  • 15,127
  • 10
  • 89
  • 104
BenSchro10
  • 326
  • 1
  • 7
7

I think you should refactor your packages in more convenient hierarchy, so they are out of the base package.

But if you can't do this, try:

<context:component-scan base-package="com.example">
    ...
    <context:exclude-filter type="regex" expression="com\.example\.ignore.*"/>
</context:component-scan>

Here you could find more examples: Using filters to customize scanning

Dirk
  • 3,030
  • 1
  • 34
  • 40
richarbernal
  • 1,063
  • 2
  • 14
  • 32
  • Thanks, in principle I agree with the idea of refactoring-- it was my first thought. Unfortunately, it's not really a great option for my particular situation. – HolySamosa May 23 '12 at 18:47
  • Good package design can avoid this situations, but if you can't... you can't hahaha, :) – richarbernal May 23 '12 at 18:50
4

One thing that seems to work for me is this:

@ComponentScan(basePackageClasses = {SomeTypeInYourPackage.class}, resourcePattern = "*.class")

Or in XML:

<context:component-scan base-package="com.example" resource-pattern="*.class"/>

This overrides the default resourcePattern which is "**/*.class".

This would seem like the most type-safe way to ONLY include your base package since that resourcePattern would always be the same and relative to your base package.

leeor
  • 17,041
  • 6
  • 34
  • 60
3

Just an addition to existing answers.
If you want to exclude classes from sub-packages but not from the base package then you can change "com.example.ignore.* to "com.example.ignore.*..*" as follows

Verified this in spring-boot: 2.4.1

Taken code snippet from this answer

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan(basePackages = { "com.example" },
    excludeFilters = @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "com.example.ignore.*..*"))
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
dkb
  • 4,389
  • 4
  • 36
  • 54
1

You can also use @SpringBootApplication, which according to Spring documentation does the same functionality as the following three annotations: @Configuration, @EnableAutoConfiguration @ComponentScan in one annotation.

@SpringBootApplication(exclude= {Foo.class})
public class MySpringConfiguration {}
dorony
  • 1,008
  • 1
  • 14
  • 31
  • 5
    According to Javadoc, `exclude` is to _Exclude specific auto-configuration classes_, not all classes from component scan. If you try, you'll get an error "_The following classes could not be excluded because they are not auto-configuration classes_". – Abhijit Sarkar Sep 25 '20 at 17:53
-1

You can also include specific package and excludes them like :

Include and exclude (both)

 @SpringBootApplication
        (
                scanBasePackages = {
                        "com.package1",
                        "com.package2"
                },
                exclude = {org.springframework.boot.sample.class}
        )

JUST Exclude

@SpringBootApplication(exclude= {com.package1.class})
public class MySpringConfiguration {}
Rishabh Agarwal
  • 2,374
  • 1
  • 21
  • 27
  • 8
    According to Javadoc, `exclude` is to _Exclude specific auto-configuration classes_, not all classes from component scan. If you try, you'll get an error "_The following classes could not be excluded because they are not auto-configuration classes_". – Abhijit Sarkar Sep 25 '20 at 17:54