我正在使用SpringBoot 2.3.3.RELEASE,我有以下Web控制器和服务。
myapp
- controllers
- ProductController
- OrderController
- services
- ProductService
- OrderService
ProductController
只取决于ProductService
,OrderController
只取决于OrderService
。
以下是我的 SpringBoot 主入口点类:
package com.sivalabs.myapp;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
我有一个用于测试ProductController
@WebMvcTest
控制器,如下所示:
@WebMvcTest(controllers = ProductController.class)
class ProductControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private ProductService productService;
//some tests
}
使用此配置,一切都很好。
我正在尝试使用一些带有不同包名称的 Spring 组件的外部库,所以我想覆盖@ComponentScan
如下:
package com.sivalabs.myapp;
import com.somelib.BeanConfig;
@SpringBootApplication
@ComponentScan(basePackageClasses = {Application.class, BeanConfig.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
当我在主入口点类中包含@ComponentScan
并运行基于@WebMvcTest
的测试ProductControllerTest
时,除了ProductService
SpringBoot 还尝试初始化OrderService
。理想情况下,ProductControllerTest
不应该加载OrderService
因为ProductController
不依赖于OrderService
。这是一个错误吗?
解决方法:
- 如果我使用
@ComponentScan
元注释的使用方式@SpringBootApplication
并包括basePackageClasses
它工作正常。
package com.sivalabs.myapp;
@SpringBootApplication
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) },
basePackageClasses = {Application.class, BeanConfig.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- 如果我添加另一个配置类并在该类上添加
@ComponentScan
,则无需在主入口点类上添加@ComponentScan
,然后它工作正常。
package com.sivalabs.myapp.config;
@Configuration
@ComponentScan(basePackageClasses = {BeanConfig.class})
public class AppConfig {
}
是组件扫描过程中的错误还是按预期工作?
它按预期工作。 @SpringBootAplication已经@ComponentScan过滤器,并在 workaroud #1 中重新声明它没有意义,对吧?
原始代码的问题在于@ComponentScan覆盖排除在注释内部应用的过滤器@SpringBootApplocation。而且不排除内容,因此当@WebMvc尝试使用过滤器请求部分上下文时,它会失败,并且会加载整个上下文。
只需检查每个场景中针对上下文初始化了哪些 bean。并坚持使用解决方案 2。@SpringBootTest将扫描应用程序类所在的包,任何其他包都应按配置进行扫描。那更脆弱吧?:)