弹簧启动组件扫描排除不排除

2022-09-02 20:40:45

我有一个简单测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SimpleTestConfig.class)
public class SimpleTest {
    @Test
    public void test() {
        assertThat(true);
    }
}

和此测试的配置

@SpringBootApplication
@ComponentScan(basePackageClasses = {
        SimpleTestConfig.class,
        Application.class
},
        excludeFilters = @ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,
                classes = Starter.class))
public class SimpleTestConfig {
}

我正在尝试排除初学者

package application.starters;

import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

@Component
public class Starter {
    @PostConstruct
    public void init(){
        System.out.println("initializing");
    }
}

应用程序类如下所示:

package application;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import static org.springframework.boot.SpringApplication.run;

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

但是由于一个非常奇怪的原因,Starter类仍在初始化。

谁能解释为什么不排除我的班级?ComponentScan excludeFiltersStarter


答案 1

每个组件扫描都会单独进行过滤。当您从 中排除 时,初始化 ,它自己不排除 。使用 ComponentScan 的简洁方法是让每个 ComponentScan 扫描单独的包,这样每个过滤器都可以正常工作。当 2 个单独的 ComponentScan 扫描同一个包(如在测试中)时,这不起作用。Starter.classSimpleTestConfigSimpleTestConfigApplication@ComponentScanStarter

欺骗它的一种方法是提供一个模拟豆:Starter

import org.springframework.boot.test.mock.mockito.MockBean;

public class SimpleTest {
    @MockBean
    private Starter myTestBean;
    ...
}

Spring将使用该模拟而不是实类,因此不会调用该方法。@PostConstruct

其他常见解决方案:

  • 不要在任何单元测试中直接使用Application.class
  • 使用弹簧轮廓和注释,例如在类上@Profile("!TEST")Starter
  • 在类上使用弹簧 Boot 注释@ConditionalOn...Starter

答案 2

您可以定义自定义组件扫描筛选器以将其排除。

示例代码将如下所示:

@SpringBootApplication()
@ComponentScan(excludeFilters=@Filter(type = FilterType.REGEX, pattern="com.wyn.applications.starter.Starter*"))
public class SimpleTestConfig {

}

这对我有用。

有关进一步阅读,请转到此博客


推荐