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
-
The automatic configuration class is not loaded: Module A
@AutoConfiguration
Class is not effective in module B. - Dependency conflict: Third-party libraries indirectly introduce dependencies that conflict with module A (such as inconsistent version of the log framework).
-
Conditional annotation restrictions:Configuration class cause
@ConditionalOnClass
Skip if the conditions are not met. - 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/resources
Create 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 may
META-INF/spring
Show as。
-
Solution:
- Delete the wrong path.
- Right-click
src/main/resources
→ New → Directory→ EnterMETA-INF/spring
。 - create
document.
3. Detailed explanation of core knowledge points
3.1 Spring Boot automatic configuration mechanism
3.1.1 Core Components
-
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.
-
-
Automatic configuration class:
- pass
@AutoConfiguration
Mark, cooperateDocument statement.
- pass
-
Loading process:
-
Spring Boot :pass
File loading automatic configuration class.
-
Spring Boot : Recommended
。
-
Spring Boot :pass
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
-
Phenomenon:
META-INF/spring
The directory is displayed as。
-
solve:
- Delete the wrong path.
- Right-click
src/main/resources
→ New → Directory→ EnterMETA-INF/spring
。 - Recreate
document.
4.2 Trap 2: Configuration file overwrite
-
Phenomenon: Module B
Override the configuration of module A.
-
solve:
- Place the configuration file of module A in
src/main/resources/config/
In the directory. - Specify the activation configuration file in module B:
- Place the configuration file of module A in
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
-
Phenomenon:
Configuration 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 with
Origin
Header 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
-
The automatic configuration class must be passed
Explicit declaration:
- For example: in module A
META-INF/spring/
All autoconfiguration classes are listed in this.
- For example: in module A
-
Bean registration required
@Bean
Or implementWebMvcConfigurer
:- like
CorsFilter
pass@Bean
register,WebMvcConfigurer
The method needs to be@AutoConfiguration
Implemented in the class.
- like
-
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:
@AutoConfiguration
is 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:
-
Automatically register to Spring container:quilt
@AutoConfiguration
The marked class will be automatically recognized by Spring Boot as an automatic configuration class. -
Load on demand: Combined with the conditional annotation (such as
@ConditionalOnClass
), effective only when the conditions are met. - Modular configuration: Suitable for multi-module projects, encapsulating configuration logic into independent modules.
-
Automatically register to Spring container:quilt
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
@AutoConfiguration
Marked as an automatic configuration class. - In module A
META-INF/spring/
The class is declared in the file. - After Module B refers to Module A, Spring Boot will automatically load without manual import.
- pass
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:
@Bean
is the core annotation of the Spring framework, used toThe object returned by the method is registered as a Spring container-managed bean。 -
effect:
- Explicitly declare a bean: Developers define the creation logic of beans through methods.
-
Dependency injection: Method parameters support dependency injection (such as
@Autowired
)。 - Flexible control: You can specify the bean scope, initialization method, conditions, etc.
- 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
@Bean
WilldataSource()
The method returnsHikariDataSource
Register as a Bean. - Combined
@ConditionalOnMissingBean
Avoid conflicts with user-defined beans.
- pass
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 library
ObjectMapper
Register as Spring Bean for global use.
- Convert third-party library
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:
-
@Configuration
It is the "identity" of the configuration class. -
@Bean
It 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:
-
@AutoConfiguration
Cooperatedocument,No manual registration required。
- 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. - exist
Register in Spring Boot method.
-
-
in conclusion: In Spring Boot,
@AutoConfiguration
It 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
@Conditional
annotation).
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:
- @AutoConfiguration: declared as an automatic configuration class.
- @ConditionalOnWebApplication: Only effective in the Servlet environment.
-
@Bean:Will
CorsFilter
Register as a Bean. - 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:
- Not here
Declare the class in the file.
- Dependencies are not properly introduced (such as module B does not depend on module A).
- Conditional annotation is not met (e.g.
@ConditionalOnClass
class does not exist).
- Not here
-
Solution:
- examine
Is the file path correct?
- Make sure that the POM of module B contains the dependencies of module A.
- Search in the startup log
Positive matches
, confirm whether the conditions are met.
- examine
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 implementationWebMvcConfigurer
Interface or use@Bean
registerWebMvcConfigurer
Add 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!