Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot ComponentScan excludeFIlters not excluding

I am having a SimpleTest :

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

and a configuration for this test :

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

I am trying to exclude the Starter class

package application.starters;

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

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

And the Application class looks like this :

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

But for a very weird reason the Starter class is still getting initialized.

Can anyone explain why the ComponentScan excludeFilters is not excluding my Starter class ?

like image 261
Daniel Taub Avatar asked Jan 04 '18 20:01

Daniel Taub


People also ask

How do I exclude a configuration class in Spring Boot?

16.2 Disabling Specific Auto-configuration Classes If the class is not on the classpath, you can use the excludeName attribute of the annotation and specify the fully qualified name instead. Finally, you can also control the list of auto-configuration classes to exclude by using the spring. autoconfigure.

Which annotation can be used to replace @configuration @EnableAutoConfiguration and @ComponentScan?

Actually the @SpringBootApplication annotation is equivalent to using @Configuration , @EnableAutoConfiguration and @ComponentScan with their default attributes.

What is exclude in @SpringBootApplication?

exclude , not excludes as in the release notes. This helps prevent Spring Boot from loading autoconfig classes in the presence of multiple @EnableAutoConfiguration / @SpringBootApplication annotations.

How do I disable ComponentScan?

To disable the default filter, set the useDefaultFilters element of the @ComponentScan annotation to false.


1 Answers

Each component scan does filtering individually. While you exclude Starter.class from SimpleTestConfig, SimpleTestConfig initializes Application, which does it's own @ComponentScan without excluding Starter. The clean way of using ComponentScan is for each ComponentScan to scan separate packages, that way each filter works fine. When 2 separate ComponentScans scan the same package (as in your tests), this does not work.

One way to trick this is to provide a mock Starter bean:

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

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

Spring will use that mock instead of the real class, thus the @PostConstruct method will not be called.

Other common solutions:

  • Do not directly use Application.class in any unit test
  • Use Spring profile and annotations such as @Profile("!TEST") on the Starter class
  • Use a spring Boot @ConditionalOn... annotation on the Starter class
like image 84
tkruse Avatar answered Oct 22 '22 02:10

tkruse