SoFunction
Updated on 2025-05-22

Solution to the failure problem of SpringBoot multi-module automatic configuration

1. Problem background and scene

1.1 Scene Description

Assume that there are two modules:

  • Module A: Provides general configuration (such as cross-domain configuration, global exception handling, interceptor).
  • Module B: Refer to module A, but the configuration of module A is not effective (such as the cross-domain configuration is invalid and the exception handler does not catch the exception).

1.2 Core issues

  1. The automatic configuration class is not loaded: Module A@AutoConfigurationClass is not effective in module B.
  2. Dependency conflict: Third-party libraries indirectly introduce dependencies that conflict with module A (such as inconsistent version of the log framework).
  3. Conditional annotation restrictions:Configuration class cause@ConditionalOnClassSkip if the conditions are not met.
  4. Packet scan path error: Module B does not scan the package path to module A.

2. Solution

2.1 Step 1: Declare the automatic configuration class

2.1.1 UseMETA-INF/spring/

In module Asrc/main/resourcesCreate the following path in the directory:

src/main/resources/
└── META-INF/
    └── spring/
        └── 

The file content is a fully qualified name of an automatic configuration class per line:

2.1.2 Code example: Automatic configuration class

// Module A@AutoConfiguration
@ConditionalOnWebApplication(type = ) // Only effective in Servlet environmentpublic class ResourcesConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // Global performance interceptor        (new PlusWebInvokeTimeInterceptor())
                .addPathPatterns("/**") // Intercept all paths
                 .excludePathPatterns("/actuator/**"); // Exclude monitoring endpoints
     }

     @Override
     public void addResourceHandlers(ResourceHandlerRegistry registry) {
         // Static resource processing (such as Swagger)
         ("/docs/**")
                 .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
     }

     /**
      * Cross-domain configuration (registered via @Bean)
      */
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        (true);
        ("*"); // All sources are allowed        ("*"); // All request headers are allowed        ("*"); // Allow all HTTP methods        (1800L); // Preflight request cache time        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        ("/**", config);
        return new CorsFilter(source);
    }
}

2.2 Step 2: Ensure the global exception processor takes effect

2.2.1 Global Exception Handler Code

// Module A@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler()
    public ResponseEntity<String> handleHttpRequestMethodNotSupported(
            HttpRequestMethodNotSupportedException e, HttpServletRequest request) {
        ("Request address'{}', Not supported'{}'ask", (), ());
        return (HttpStatus.METHOD_NOT_ALLOWED)
                .body("The request method is not supported: " + ());
    }

    @ExceptionHandler()
    public ResponseEntity<ErrorResponse> handleServiceException(
            ServiceException e, HttpServletRequest request) {
        ("Business exception: {}", ());
        return (())
                .body(new ErrorResponse((), ()));
    }

    @ExceptionHandler()
    public ResponseEntity<String> handleGlobalException(Exception e) {
        ("Global exception: {}", (), e);
        return (HttpStatus.INTERNAL_SERVER_ERROR)
                .body("Internal system error");
    }

    private static class ErrorResponse {
        private final int code;
        private final String message;

        public ErrorResponse(int code, String message) {
             = code;
             = message;
        }
    }
}

2.3 Step 3: Check Dependency Passing and Conflict

2.3.1 Exclude indirect dependency conflicts

Assume that module B referencesmybatis-spring-boot-starter, and the dependency is introduced indirectlyspring-boot-starter-logging(Creating a log framework conflict). Need to be excluded from the POM:

<!-- ModuleBof -->
<dependency>
    <groupId></groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.1</version>
    <exclusions>
        <exclusion>
            <groupId></groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

2.3.2 Check the dependency tree

Use the Maven or Gradle command to view the dependency tree:

# Maven
mvn dependency:tree | grep -i logback

# Gradle
./gradlew dependencies --configuration compileClasspath

2.4 Step 4: Ensure the package scanning path is correct

2.4.1 Explicitly specify the scan path

Set in the startup class of module BscanBasePackages

// Module B start class@SpringBootApplication(
    scanBasePackages = {
        "",
        "",
        ""
    }
)
public class ModuleBApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication();
        ("dev"); // Activate the development environment configuration        (args);
    }
}

2.4.2 Package structure optimization

Make sure that the package path of module A is a subpackage of module B startup class:

├── moduleA
│   ├── config
│   │   └── 
│   └── handler
│       └── 
└── moduleB
    ├── controller
    │   └── 
    └── 

2.5 Step 5: Verify the condition annotation

2.5.1 Example: Attribute-based conditions

// Module A@Configuration
@ConditionalOnProperty(name = "", havingValue = "true")
public class FeatureAutoConfiguration {
    @Bean
    public FeatureService featureService() {
        return new FeatureServiceImpl();
    }
}

existActivation conditions in:

feature:
  enabled: true

2.6 Step 6: Troubleshooting IDEA path problems

2.6.1 Ensure the directory structure is correct

  • Error path: IDEA mayMETA-INF/springShow as
  • Solution
    1. Delete the wrong path.
    2. Right-clicksrc/main/resources → New → Directory→ EnterMETA-INF/spring
    3. createdocument.

3. Detailed explanation of core knowledge points

3.1 Spring Boot automatic configuration mechanism

3.1.1 Core Components

  1. Conditional annotation
    • @ConditionalOnClass: Effective when the classpath has a specified class.
    • @ConditionalOnMissingBean: Effective if there is no specified bean in the container.
    • @ConditionalOnProperty: Effective when the attribute exists and meets the conditions.
    • @ConditionalOnWebApplication: Only effective in the web environment.
  2. Automatic configuration class
    • pass@AutoConfigurationMark, cooperateDocument statement.
  3. Loading process
    • Spring Boot :passFile loading automatic configuration class.
    • Spring Boot : Recommended

3.1.2 Comparison of old and new mechanisms

characteristic (old) (new)
File path META-INF/ META-INF/spring/org...
Format EnableAutoConfiguration key needs to be declared List class names directly without key-value pairs
performance Global scan, possible redundant configuration loading Loading on demand, better performance

3.2 Dependency Management

3.2.1 Exclude dependency conflicts

<!-- ModuleBof -->
<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter</artifactId>
    <exclusions>
        <exclusion>
            <groupId></groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3.2.2 Introducing necessary dependencies

<!-- Introducedlog4j2 -->
<dependency>
    <groupId></groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

3.3 Advanced usage of conditional annotations

3.3.1 Combination conditions

@Configuration
@ConditionalOnClass() // The classpath has RedisClient@ConditionalOnProperty(name = "", matchIfMissing = true) // Take effect when the attribute exists or is not configuredpublic class RedisAutoConfig {
    // Configuration logic}

3.3.2 Priority control

@AutoConfiguration(after = )
public class MyConfig {
    // The configuration class will be loaded after AnotherConfig}

3.4 Multi-module package scanning

3.4.1 Dynamic Scan Strategy

// Dynamically import configuration classes using @Import@Import({, })
public class ModuleBApplication {
    // ...
}

4. Common traps and solutions

4.1 Trap 1: IDEA path error

  • PhenomenonMETA-INF/springThe directory is displayed as
  • solve
    1. Delete the wrong path.
    2. Right-clicksrc/main/resources → New → Directory→ EnterMETA-INF/spring
    3. Recreatedocument.

4.2 Trap 2: Configuration file overwrite

  • Phenomenon: Module BOverride the configuration of module A.
  • solve
    1. Place the configuration file of module A insrc/main/resources/config/In the directory.
    2. Specify the activation configuration file in module B:

4.3 Trap 3: Profile not activated

  • Phenomenon: Environment-specific configurations are not effective.
  • solve
# Specify Profile at startupjava -jar  --=dev

4.4 Trap 4: Spring Boot compatibility issues

  • PhenomenonConfiguration failed.
  • solve

    Migrate configuration to a new path:

# META-INF/spring/ of module A

5. Methods for verifying the implementation of configuration

5.1 Start log checking

  • Log Level
=DEBUG
  • Key logs
Positive matches:
  - ResourcesConfig ()
  - GlobalExceptionHandler ()

5.2 Bean injection verification

// Test class for module B@RestController
public class HealthCheckController {
    @Autowired
    private CorsFilter corsFilter;

    @GetMapping("/health/cors")
    public String health() {
        return "CorsFilter: " + ().getName();
    }
}

5.3 Cross-domain configuration testing

5.3.1 Test steps

  • Send withOriginHeader request:
curl -H "Origin: " -X GET http://localhost:8080/api/test

Expected response header

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS

5.4 Exception processor verification

5.4.1 Test business exceptions

//Module B Controller@RestController
public class TestController {
    @GetMapping("/test")
    public ResponseEntity<String> test() {
        throw new ServiceException("Custom Exception", HttpStatus.BAD_REQUEST);
    }
}

Expected response

{
    "code": 400,
    "message": "Custom Exception"
}

6. Complete solution code example

6.1 POM configuration of module A

<!-- ModuleAof -->
<dependencies>
    <dependency>
        <groupId></groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId></groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

6.2 POM configuration of module B

<!-- ModuleBof -->
<dependencies>
    <dependency>
        <groupId></groupId>
        <artifactId>moduleA</artifactId>
        <version>1.0.0</version>
    </dependency>
    <dependency>
        <groupId></groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

6.3 Startup Class of Module B

// Module B start class@SpringBootApplication(
    scanBasePackages = {
        "",
        "",
        ""
    }
)
public class ModuleBApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication();
        ("dev"); // Activate the development environment configuration        (args);
    }
}

6.4 Automatic configuration file for module A

# META-INF/spring/ of module A

7. Summary and best practices (code perspective)

7.1 Core Summary

  1. The automatic configuration class must be passedExplicit declaration
    • For example: in module AMETA-INF/spring/All autoconfiguration classes are listed in this.
  2. Bean registration required@BeanOr implementWebMvcConfigurer
    • likeCorsFilterpass@Beanregister,WebMvcConfigurerThe method needs to be@AutoConfigurationImplemented in the class.
  3. The package scan path must cover all modules
    • The startup class of module B needs to explicitly scan the package path of module A.

7.2 Best Practice Code Template

7.2.1 Automatic configuration class template for module A

@AutoConfiguration
@ConditionalOnClass() // Depend on Servlet environmentpublic class ResourcesConfig implements WebMvcConfigurer {

    // Cross-domain, interceptor and other configurations
    @Bean
    public GlobalExceptionHandler globalExceptionHandler() {
        return new GlobalExceptionHandler(); // Manually register exception handler    }
}

7.2.2 Global Exception Processor Template

@Slf4j
@RestControllerAdvice(basePackages = {"", ""})
public class GlobalExceptionHandler {

    @ExceptionHandler()
    public ResponseEntity<String> handleGlobalException(Exception e) {
        ("Global exception: {}", (), e);
        return (HttpStatus.INTERNAL_SERVER_ERROR)
                .body("Internal system error");
    }
}

8. Appendix: Tools and Commands

8.1 Dependency tree analysis

mvn dependency:tree

8.2 Log-level debugging

java -jar  --=DEBUG

8.3 Inter-module dependency verification

# Gradle checks for dependency conflicts./gradlew dependencies --configuration compileClasspath

9. Supplement

1. @AutoConfiguration annotation details

1.1 Basic Concept

  • definition
    @AutoConfigurationis an annotation introduced by Spring Boot, used to mark a class asAutomatic configuration class, its function isSimplify the declaration of automatic configuration classes, no need to beMETA-INF/Manual registration in.
  • effect
    1. Automatically register to Spring container:quilt@AutoConfigurationThe marked class will be automatically recognized by Spring Boot as an automatic configuration class.
    2. Load on demand: Combined with the conditional annotation (such as@ConditionalOnClass), effective only when the conditions are met.
    3. Modular configuration: Suitable for multi-module projects, encapsulating configuration logic into independent modules.

1.2 The difference between @AutoConfiguration and @Configuration

characteristic @AutoConfiguration @Configuration
effect Automatic configuration class, no manual registration required Regular configuration class, you need to register through other methods
Automatic registration Automatically register to Spring container (needed to cooperate) Need to be explicitly registered (such as via component scanning or @Import)
Applicable scenarios Automatic configuration scenarios (such as multi-module shared configuration) Common configuration classes (such as custom beans)
Is additional configuration required Need to be declared in the file No additional configuration required (but it needs to be scanned by Spring container)
Dependencies Usually combined with @Conditional annotation Can be used independently, but bean dependencies need to be managed manually

1.3 @AutoConfiguration usage scenarios

Scenario 1: Multi-module shared configuration

// Module A@AutoConfiguration
@ConditionalOnWebApplication(type = )
public class ResourcesConfig implements WebMvcConfigurer {
    // Cross-domain configuration, interceptor, etc.}
  • Key points
    • pass@AutoConfigurationMarked as an automatic configuration class.
    • In module AMETA-INF/spring/The class is declared in the file.
    • After Module B refers to Module A, Spring Boot will automatically load without manual import.

Scene 2: Replace the old version

# Spring Boot (requires manual registration)=\
,\

  • Improvements to Spring Boot
    use@AutoConfiguration + document,No need for maintenance

2. @Bean annotation details

2.1 Basic Concept

  • definition
    @Beanis the core annotation of the Spring framework, used toThe object returned by the method is registered as a Spring container-managed bean
  • effect
    1. Explicitly declare a bean: Developers define the creation logic of beans through methods.
    2. Dependency injection: Method parameters support dependency injection (such as@Autowired)。
    3. Flexible control: You can specify the bean scope, initialization method, conditions, etc.
    4. Scope control: Specify the scope of the bean (such as singleton, prototype) through @Scope.

2.2 @Bean usage scenarios

Scenario 1: Defining the basic bean

@Configuration
public class DataSourceConfig {
    @Bean
    @ConditionalOnMissingBean() // Effective only if there is no DataSource in the container    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ("jdbc:mysql://localhost:3306/test");
        return ds;
    }
}
  • Key points
    • pass@BeanWilldataSource()The method returnsHikariDataSourceRegister as a Bean.
    • Combined@ConditionalOnMissingBeanAvoid conflicts with user-defined beans.

Scenario 2: Register a third-party library bean

@Configuration
public class JsonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        (new SimpleDateFormat("yyyy-MM-dd"));
        return mapper;
    }
}
  • Key points
    • Convert third-party libraryObjectMapperRegister as Spring Bean for global use.

Scenario 3: Scope Control

@Bean
@Scope("prototype") // Create a new instance every time you requestpublic MyPrototypeBean prototypeBean() {
    return new MyPrototypeBean();
}

3. Collaborative relationship between @Configuration and @Bean

3.1 Basic configuration class structure

@Configuration // Mark as configuration classpublic class MyAutoConfiguration {
    @Bean // Define Bean    public MyService myService() {
        return new MyServiceImpl();
    }
}
  • Key points
    • @ConfigurationIt is the "identity" of the configuration class.
    • @BeanIt is a "tool" that defines a bean in the configuration class.

4. Why do you have to use @AutoConfiguration? Can @Configuration be replaced?

4.1 The situation where @AutoConfiguration must be used

  • Scene: In a multi-module project,The configuration of module A needs to be automatically loaded by module B
  • reason
    1. @AutoConfigurationCooperatedocument,No manual registration required
    2. If only@Configuration, it needs to be loaded explicitly in the following ways:
      • Specify the scan path in the startup class of module B.
      • pass@Import()Import.
      • existRegister in Spring Boot method.
  • in conclusion: In Spring Boot,@AutoConfigurationIt is a simpler solution.

4.2 Alternatives to @Configuration

// Scheme 1: explicitly scan module A's package in module B startup class@SpringBootApplication(scanBasePackages = {"", ""})
public class ModuleBApplication { ... }

// Scheme 2: Use @Import to import the configuration class@Configuration
@Import()
public class ModuleBConfig { ... }
  • shortcoming
    • The package path or import relationship needs to be manually maintained.More coupling
    • Not qualified loading capability (unless manually added@Conditionalannotation).

5. Analysis of key annotations in the sample code

5.1 ResourcesConfig Example

@AutoConfiguration
@ConditionalOnWebApplication(type = )
public class ResourcesConfig implements WebMvcConfigurer {
    @Bean
    public CorsFilter corsFilter() { ... }

    @Override
    public void addInterceptors(InterceptorRegistry registry) { ... }
}
  • Key points
    1. @AutoConfiguration: declared as an automatic configuration class.
    2. @ConditionalOnWebApplication: Only effective in the Servlet environment.
    3. @Bean:WillCorsFilterRegister as a Bean.
    4. Implement WebMvcConfigurer: Directly extend Spring MVC configuration through the inheritance interface.

5.2 Global Exception Handler Example

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler()
    public ResponseEntity<String> handleGlobalException(Exception e) { ... }
}
  • Key points
    • @RestControllerAdvice: Marked as a global exception handling class.
    • No need@Bean, because Spring automatically recognizes through component scanning.

6. FAQs and Answers

Q1: Why is my automatic configuration class not loaded?

  • Possible Causes
    1. Not hereDeclare the class in the file.
    2. Dependencies are not properly introduced (such as module B does not depend on module A).
    3. Conditional annotation is not met (e.g.@ConditionalOnClassclass does not exist).
  • Solution
    • examineIs the file path correct?
    • Make sure that the POM of module B contains the dependencies of module A.
    • Search in the startup logPositive matches, confirm whether the conditions are met.

Q2: What is the difference between @Bean and @Component?

annotation Range of action Use scenarios
@Bean Method level Define the creation logic of beans in the configuration class
@Component Class level Automatically register beans through component scanning

Q3: Why does automatic configuration classes need to implement WebMvcConfigurer?

  • reason
    Spring MVC's extension mechanism allows implementationWebMvcConfigurerInterface or use@BeanregisterWebMvcConfigurerAdd interceptors, cross-domain configurations, etc.
  • Example
@Override
public void addInterceptors(InterceptorRegistry registry) {
    (new MyInterceptor());
}

7. Complete automatic configuration class code example

// Module A@AutoConfiguration
@ConditionalOnWebApplication(type = )
public class ResourcesConfig implements WebMvcConfigurer {
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        ("*");
        ("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        ("/**", config);
        return new CorsFilter(source);
    }

    @Bean
    public MyInterceptor myInterceptor() {
        return new MyInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        (myInterceptor())
                .addPathPatterns("/**");
    }

    @Bean
    @ConditionalOnMissingBean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

8. Key configuration file description

8.1 File

# META-INF/spring/ of module A
  • effect
    Tell Spring Boot which classes are automatic configuration classes.No manual registration required

8.2 (Spring Boot compatible)

# META-INF/ of module A=\
,\

  • Compatibility description
    Spring Boot supports two ways to use it at the same time, but it is recommended to use it.@AutoConfiguration

The above is the detailed content of the solution to the problem of automatic configuration failure of SpringBoot multi-module. For more information about the automatic configuration failure of SpringBoot multi-module, please pay attention to my other related articles!