SpringBoot @WebMvcTest is loading non-dependent beans when @ComponentScan is used along with @SpringBootApplication

huangapple go评论75阅读模式
英文:

SpringBoot @WebMvcTest is loading non-dependent beans when @ComponentScan is used along with @SpringBootApplication

问题

我正在使用 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;
   
    //一些测试
}

在这个配置下一切都运行得非常完美。

我尝试在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。这是一个错误吗?

解决方法:

  1. 如果我使用与 @SpringBootApplication 元注解上使用的方式相同的方式使用 @ComponentScan,并包括 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);
    }

}
  1. 如果我不是在主入口类上添加 @ComponentScan,而是添加另一个配置类并在该类上添加 @ComponentScan,那么它可以正常工作。
package com.sivalabs.myapp.config;

@Configuration
@ComponentScan(basePackageClasses = {BeanConfig.class})
public class AppConfig {

}

这是组件扫描过程中的错误吗,还是按预期工作的?

英文:

I am using SpringBoot 2.3.3.RELEASE and I have following web controllers and Services.

myapp
  - controllers
      - ProductController
      - OrderController
  - services
      - ProductService
      - OrderService

ProductController only depends on ProductService and OrderController only depends on OrderService.

Following is my SpringBoot main entrypoint class:

package com.sivalabs.myapp;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

I have an @WebMvcTest controller for testing ProductController as follows:

@WebMvcTest(controllers = ProductController.class)
class ProductControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private ProductService productService;
   
    //some tests
}

Everything works perfectly fine with this configuration.

I am trying to use some external library with Spring components which has different package name, so I want to override @ComponentScan as follows:

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);
    }

}

When I include @ComponentScan on my main entrypoint class and run my @WebMvcTest based test ProductControllerTest then in addition to ProductService SpringBoot is trying to initialise OrderService also. Ideally ProductControllerTest should not load OrderService as ProductController doesn't depend on OrderService. Is it a bug?

Workarounds:

  1. If I use @ComponentScan the way it is used on @SpringBootApplication meta-annotation and include basePackageClasses it is working fine.
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);
    }

}
  1. Instead of adding @ComponentScan on main entrypoint class if I add another configuration class and add @ComponentScan on that class then it's working fine.
package com.sivalabs.myapp.config;

@Configuration
@ComponentScan(basePackageClasses = {BeanConfig.class})
public class AppConfig {

}

Is it a bug in component scanning process or is it working as expected?

答案1

得分: 1

它按预期工作。
@SpringBootAplication 已经使用过滤器进行了 @ComponentScan,重新声明它,就像在解决方法#1中那样,是没有意义的,对吧?

原始代码的问题在于 @ComponentScan 会覆盖在 @SpringBootApplocation 注解内部应用的排除过滤器。所以当 @WebMvc 尝试使用过滤器请求上下文的一部分时,它会失败,并且会加载整个上下文。

只需检查在每种情况下为上下文初始化了哪些 bean。并且坚持使用解决方案2。@SpringBootTest 将扫描放置应用程序类的包,任何附加包都应该由配置来扫描。这甚至更加灵活,对吧? SpringBoot @WebMvcTest is loading non-dependent beans when @ComponentScan is used along with @SpringBootApplication

英文:

It working as expected.
@SpringBootAplication already have @ComponentScan with filters, and redeclare it as in workaroud #1 doesn't make sense, right?

Problem With original code is that @ComponentScan overrides exclude filters applied inside @SpringBootApplocation annotation. And stuff is not excluded, so when @WebMvc tries to request part of context using filters it fails, and entire context is loaded.

Just check what beans are initialized for context in each scenario. And stick to solution 2. @SpringBootTest will scan packages where application class is places, and any additional packages should be scanned by configurations. That is even more flixible right? SpringBoot @WebMvcTest is loading non-dependent beans when @ComponentScan is used along with @SpringBootApplication

huangapple
  • 本文由 发表于 2020年8月27日 10:51:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/63608433.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定