Search code examples
spring-bootannotationsspring-integrationspring-annotationscomponent-scan

IntegrationComponentScan with an explicit basePackages required in Spring Boot?


I have a Spring Boot application (using Spring Boot 2.4.11) where I'm using Spring Integration. I added the org.springframework.boot:spring-boot-starter-integration and hence I expected @IntegrationComponentScan to be active by default. Indeed, I find Issue 2037 that seems to suggest this. Also, I see that annotation on org.springframework.boot.autoconfigure.integration.IntegrationAutoConfigurationScanRegistrar.IntegrationComponentScanConfiguration.

However, my @MessagingGateway annotated interfaces were not taken up by Spring. I tried to add an explicit @IntegrationComponentScan on one of my @Configuration classes, but it didn't work either.

It started to work once I also specified an explicit basePackages value for that annotation, so:

@Configuration
@IntegrationComponentScan(basePackages = "com.example.app.integration")
public class MyConfigurationClass {
}

and of course my annotated interfaces are in a package below com.example.app.integration.

Am I missing something? I couldn't find any reference to @IntegrationComponentScan in Spring Boot documentation. Other similar annotations (like @EnableJpaRepositories for Spring Data or @EntityScan) are not strictly necessary, unless you need to customize the scanning scope.

I also found Issue 3375, that seems to suggest that I should look at @AutoConfigurationPackage, but:

  • I can't find any mention to this annotation in Spring Boot documentation
  • I suspect this will apply to ANY other "scan" annotation enabled by Spring Boot, so my basePackages in this case must probably point to some package very close to the "root" of my application
  • why isn't this annotation required by other @*Scan annotations like the above ones?

Solution

  • I think you need to show your project structure. It works as expected:

    1. I have an interface like com.example.integration.gateway.MyGateway

    2. My main class is in the com.example.integration.IntegrationApplication with a content like:

      @SpringBootApplication
      public class IntegrationApplication {
      

    It still works even if I have that MyGateway in the com.example.integration package.

    To conclude. The @SpringBootApplication is marked with the @ComponentScan where Spring starts scanning components from the package where this @SpringBootApplication is declared and all the way down to its sub-packages.

    If your components are in a different from @SpringBootApplication class, then consider to have it customized via its scanBasePackages property:

    /**
     * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}
     * for a type-safe alternative to String-based package names.
     * <p>
     * <strong>Note:</strong> this setting is an alias for
     * {@link ComponentScan @ComponentScan} only. It has no effect on {@code @Entity}
     * scanning or Spring Data {@link Repository} scanning. For those you should add
     * {@link org.springframework.boot.autoconfigure.domain.EntityScan @EntityScan} and
     * {@code @Enable...Repositories} annotations.
     * @return base packages to scan
     * @since 1.3.0
     */
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};
    

    Everything else needs an investigation already inside your project. If you can share that with us, we can take a look and find something.

    UPDATE

    Turned out when an XML configuration for <int:gateway> is in use, Spring Boot auto-configuration for @IntegrationComponentScan backs-off and requires to be provided explicitly to make @MessagingGateway interfaces to be visible. This problem was fixed in Spring Boot 3.0 as a side-effect of some other fix.