Исключить @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 {}
Но это, похоже, не исключает компонент из сканирования, как я хочу.
Как его исключить?
Ответы
Ответ 1
Конфигурация выглядит хорошо, за исключением того, что вы должны использовать excludeFilters
вместо excludes
:
@Configuration @EnableSpringConfigured
@ComponentScan(basePackages = {"com.example"}, excludeFilters={
@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class)})
public class MySpringConfiguration {}
Ответ 2
Использование явных типов в фильтрах сканирования уродливо для меня. Я считаю, что более элегантный подход заключается в создании собственной аннотации маркера:
public @interface IgnoreDuringScan {
}
Отметьте компонент, который следует исключить из него:
@Component("foo")
@IgnoreDuringScan
class Foo {
...
}
И исключить эту аннотацию из сканирования компонентов:
@ComponentScan(excludeFilters = @Filter(IgnoreDuringScan.class))
public class MySpringConfiguration {}
Ответ 3
Другой подход - использовать новые условные аннотации.
Поскольку 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]
}
}
Условная логика может быть основана на контексте, потому что у вас есть доступ к bean factory. Например, если компонент "Бар" не зарегистрирован как bean:
return !context.getBeanFactory().containsBean(Bar.class.getSimpleName());
С помощью Spring Boot (он должен использоваться для КАЖДОГО нового проекта Spring), вы можете использовать эти условные аннотации:
-
@ConditionalOnBean
-
@ConditionalOnClass
-
@ConditionalOnExpression
-
@ConditionalOnJava
-
@ConditionalOnMissingBean
-
@ConditionalOnMissingClass
-
@ConditionalOnNotWebApplication
-
@ConditionalOnProperty
-
@ConditionalOnResource
-
@ConditionalOnWebApplication
Вы можете избежать создания класса условий таким образом. Более подробно см. Spring Загрузочные документы.
Ответ 4
В случае, если вам необходимо определить два или более критерия 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) })
Ответ 5
В случае исключения тестового компонента или тестовой конфигурации Spring Boot 1.4 представил новые аннотации для тестирования @TestComponent
и @TestConfiguration
.
Ответ 6
У меня возникла проблема при использовании @Configuration, @EnableAutoConfiguration и @ComponentScan при попытке исключить определенные классы конфигурации. Дело в том, не работает!
В конце концов я решил проблему, используя @SpringBootApplication, который согласно документации Spring делает то же самое функциональность как три выше в одной аннотации.
Другой совет - сначала попробовать, не уточняя проверку вашего пакета (без фильтра basePackages).
@SpringBootApplication(exclude= {Foo.class})
public class MySpringConfiguration {}