it-swarm.com.ru

исключить @Component из @ComponentScan

У меня есть компонент, который я хочу исключить из @ComponentScan в конкретном @Configuration:

@Component("foo") class Foo {
...
}

В противном случае, это похоже на конфликт с каким-то другим классом в моем проекте. Я не до конца понимаю коллизию, но если я закомментирую аннотацию @Component, все будет работать так, как я хочу. Но другие проекты, использующие эту библиотеку, ожидают, что этим классом будет управлять Spring, поэтому я хочу пропустить его только в своем проекте.

Я пытался использовать @ComponentScan.Filter:

@Configuration 
@EnableSpringConfigured
@ComponentScan(basePackages = {"com.example"}, excludeFilters={
  @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class)})
public class MySpringConfiguration {}

но это не похоже на работу. Если я пытаюсь использовать FilterType.ASSIGNABLE_TYPE, я получаю странную ошибку из-за невозможности загрузить какой-то, казалось бы, случайный класс:

Причина: Java.io.FileNotFoundException: ресурс пути к классу [junit/framework/TestCase.class] не может быть открыт, потому что он не существует

Я также попытался использовать type=FilterType.CUSTOM следующим образом:

class ExcludeFooFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader,
            MetadataReaderFactory metadataReaderFactory) throws IOException {
        return metadataReader.getClass() == Foo.class;
    }
}

@Configuration @EnableSpringConfigured
@ComponentScan(basePackages = {"com.example"}, excludeFilters={
  @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class)})
public class MySpringConfiguration {}

Но это, кажется, не исключает компонент из сканирования, как я хочу.

Как мне это исключить?

57
ykaganovich

Конфигурация выглядит нормально, за исключением того, что вы должны использовать excludeFilters вместо excludes:

@Configuration @EnableSpringConfigured
@ComponentScan(basePackages = {"com.example"}, excludeFilters={
  @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class)})
public class MySpringConfiguration {}
68
Sergi Almar

Использование явных типов в фильтрах сканирования для меня ужасно. Я считаю, что более элегантный подход заключается в создании собственной аннотации маркера:

public @interface IgnoreDuringScan {
}

Отметьте компонент, который должен быть исключен с ним:

@Component("foo") 
@IgnoreDuringScan
class Foo {
    ...
}

И исключите эту аннотацию из вашего сканирования компонентов:

@ComponentScan(excludeFilters = @Filter(IgnoreDuringScan.class))
public class MySpringConfiguration {}
36
luboskrnac

Другой подход заключается в использовании новых условных аннотаций . Поскольку plain Spring 4, вы можете использовать @Conditional аннотацию:

@Component("foo")
@Conditional(FooCondition.class)
class Foo {
    ...
}

и определить условную логику для регистрации компонента Foo:

public class FooCondition implements Condition{
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // return [your conditional logic]
    }     
}

Условная логика может основываться на контексте, потому что у вас есть доступ к фабрике бинов. Например, когда компонент "Bar" не зарегистрирован как компонент:

    return !context.getBeanFactory().containsBean(Bar.class.getSimpleName());

С Spring Boot (должен использоваться для КАЖДОГО нового проекта Spring), вы можете использовать эти условные аннотации:

  • @ConditionalOnBean
  • @ConditionalOnClass
  • @ConditionalOnExpression
  • @ConditionalOnJava
  • @ConditionalOnMissingBean
  • @ConditionalOnMissingClass
  • @ConditionalOnNotWebApplication
  • @ConditionalOnProperty
  • @ConditionalOnResource
  • @ConditionalOnWebApplication

Таким способом вы можете избежать создания класса Condition. Обратитесь к документации Spring Boot для более подробной информации.

20
luboskrnac

В случае, если вам нужно определить два или более excludeFilters критерия, вы должны использовать массив. 

Для экземпляров в этом разделе кода я хочу исключить все классы в пакете org.xxx.yyy и другой определенный класс, MyClassToExclude

 @ComponentScan(            
        excludeFilters = {
                @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.xxx.yyy.*"),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MyClassToExclude.class) })
8
Enrico Giurin

У меня возникла проблема при использовании @Configuration, @EnableAutoConfiguration и @ComponentScan при попытке исключить определенные классы конфигурации, дело в том, что это не сработало! 

В конце концов я решил эту проблему с помощью @SpringBootApplication , который в соответствии с документацией Spring выполняет те же функции, что и три выше в одной аннотации.

Другой совет - сначала попробуйте без уточнения сканирования вашего пакета (без фильтра basePackages).

@SpringBootApplication(exclude= {Foo.class})
public class MySpringConfiguration {}
4
dorony

В случае исключения тестового компонента или тестовой конфигурации Spring Boot 1.4 вводит новые аннотации тестирования @TestComponent И @TestConfiguration .

1
luboskrnac

Мне нужно было исключить аудит @Aspect @Component из контекста приложения, но только для нескольких тестовых классов. Я закончил тем, что использовал @Profile ("аудит") в классе аспектов; включая профиль для обычных операций, но исключая его (не помещайте его в @ActiveProfiles) для определенных тестовых классов.

0
Miguel Pereira