Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@ComponentScan added directly and via a meta-annotation leads to multiple scanning #31704

Closed
matt-whiteman opened this issue Nov 28, 2023 · 8 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: regression A bug that is also a regression
Milestone

Comments

@matt-whiteman
Copy link

matt-whiteman commented Nov 28, 2023

Using Spring Boot 3.1.5, my main Application class was annotated with both @SpringBootApplication and @ComponentScan. The latter is necessary as we have a multi-module project that needs to exclude certain classes to avoid conflicts.

I am not able to paste our exact class names, so this is an example:

@SpringBootApplication
@ComponentScan(basePackages = "my.company.module",
    excludeFilters = {
        @Filter(type=REGEX, pattern="my\\.company\\.module\\.foo\\..*"),
        @Filter(type=REGEX, pattern="my\\.company\\.module\\.bar\\..*"),
        @Filter(type=REGEX, pattern="my\\.company\\.module\\.baz\\..*")
    },
    nameGenerator = FullyQualifiedAnnotationBeanNameGenerator.class)
public class Application {

This worked fine for scanning all our components and autowiring everything together. After upgrading to Spring Boot 3.2, the component scan seems to be running twice: once on "my.company.module" as expected with the appropriate filters, but then again on a blank package (thus re-scanning all our components and attempting to create them again, causing bean conflicts).

Using a debugger, I traced the change down into ConfigurationClassParser in spring-context, specifically to this line:

Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScan.class, ComponentScans.class);

This specifically occurs when it is processing the main application class:

In 3.1.5, this set after the function call has 1 entry with an expected base package "my.company.module" member.

In 3.2, this set has 2 entries after the function call, the first with "my.company.module" base package member, and the second with a base package of an empty array.

After doing some more testing, it seems as though starting in 3.2, each @ComponentScan is processed independently even if a package has already been scanned, causing Spring to believe that a component or bean might be duplicated when it isn't.

Ex: If my root package is "my.company" and I do a component scan of "my.company" and in another configuration have a scan of "my.company.foo", a component that appears in my.company.foo package will be detected as a duplicate bean of itself.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Nov 28, 2023
@HzjNeverStop
Copy link

HzjNeverStop commented Nov 28, 2023

I encountered the same issue where this incompatible change prevents me from controlling the scanning scope of the @SpringBootApplication annotation using excludeFilters.

I hope that the Spring Boot team can fix this issue in version 3.2.1.

@quaff
Copy link
Contributor

quaff commented Nov 28, 2023

Please share a minimal reproducer.

@wilkinsona wilkinsona added the status: waiting-for-feedback We need additional information before we can continue label Nov 28, 2023
@HzjNeverStop
Copy link

Please share a minimal reproducer.

You can use this project to reproduce this issue: https://github.com/HzjNeverStop/ComponentScanReproducer

The main branch use SpringBoot 3.1.5,ChildBean will not register. Then change the SpringBoot version to 3.2.0,ChildBean will be scan and applicaiton init fail

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Nov 28, 2023
@wilkinsona wilkinsona self-assigned this Nov 28, 2023
@wilkinsona wilkinsona removed the status: feedback-provided Feedback has been provided label Nov 28, 2023
@wilkinsona
Copy link
Member

Thanks for the sample. This appears to be a Spring Framework regression. The failure occurs with Spring Boot 3.1.5 (or 3.1.6) when Spring Framework is upgraded to 6.1. Trying various Framework versions, the problem appears to have been introduced in 6.1.0-M4. We'll transfer this to the Framework team so that they can investigate.

@wilkinsona wilkinsona removed their assignment Nov 28, 2023
@snicoll snicoll transferred this issue from spring-projects/spring-boot Nov 28, 2023
@HzjNeverStop

This comment was marked as resolved.

@snicoll

This comment was marked as resolved.

@snicoll
Copy link
Member

snicoll commented Nov 28, 2023

This seems to be a regression introduced by #30941

@snicoll snicoll added type: regression A bug that is also a regression and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Nov 28, 2023
@snicoll snicoll added this to the 6.1.2 milestone Nov 28, 2023
@snicoll snicoll changed the title Spring Boot 3.2 - ComponentScan with SpringBootApplication scanning multiple times @ComponentScan added directly and via a meta-annotation leads to multiple scanning Nov 28, 2023
@sbrannen sbrannen changed the title @ComponentScan added directly and via a meta-annotation leads to multiple scanning @ComponentScan added directly and via a meta-annotation leads to multiple scanning Nov 28, 2023
@sbrannen sbrannen self-assigned this Nov 28, 2023
@sbrannen sbrannen added the in: core Issues in core modules (aop, beans, core, context, expression) label Nov 28, 2023
@sbrannen
Copy link
Member

I plan to address this by allowing a directly present @ComponentScan annotation to always take precedence over any meta-present @ComponentScan annotations (such as the one on @SpringBootApplication).

Doing that would still allow us to support the "multiple meta-annotations" use case that we originally sought to support in 6.1 (see #30941).

In addition, the behavior for @ComponentScan would then effectively align with the behavior for @BootstrapWith in spring-test in the sense that a locally declared annotation always overrides a meta-annotation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: regression A bug that is also a regression
Projects
None yet
Development

No branches or pull requests

7 participants