从 Spring 自动装配中排除子包?

有没有一种简单的方法可以在 Spring 3.1中将包/子包从自动装配中排除?

例如,如果我想包括一个基本包 com.example的组件扫描是否有一个简单的方法来排除 com.example.ignore

(为什么? 我想从集成测试中排除一些组件)

157582 次浏览

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>

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

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.

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);
}
}

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.

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})
})

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 {
// ...
}

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 {}

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 {}

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);
}
}