Tengo un componente que quiero excluir de un @ComponentScan
en un particular @Configuration
:
@Component("foo") class Foo {
...
}
De lo contrario, parece chocar con alguna otra clase en mi proyecto. No entiendo completamente la colisión, pero si comento la @Component
anotación, las cosas funcionan como quiero. Pero otros proyectos que dependen de esta biblioteca esperan que Spring administre esta clase, por lo que quiero omitirla solo en mi proyecto.
Intenté usar @ComponentScan.Filter
:
@Configuration
@EnableSpringConfigured
@ComponentScan(basePackages = {"com.example"}, excludeFilters={
@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class)})
public class MySpringConfiguration {}
pero no parece funcionar. Si intento usar FilterType.ASSIGNABLE_TYPE
, obtengo un error extraño acerca de que no puedo cargar una clase aparentemente aleatoria:
Causado por: java.io.FileNotFoundException: recurso de ruta de clase [junit / framework / TestCase.class] no se puede abrir porque no existe
También intenté usar type=FilterType.CUSTOM
lo siguiente:
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 {}
Pero eso no parece excluir el componente del escaneo como quiero.
¿Cómo lo excluyo?
fuente
Usar tipos explícitos en los filtros de escaneo es feo para mí. Creo que un enfoque más elegante es crear su propia anotación de marcador:
@Retention(RetentionPolicy.RUNTIME) public @interface IgnoreDuringScan { }
Marque el componente que debe excluirse con él:
@Component("foo") @IgnoreDuringScan class Foo { ... }
Y excluya esta anotación de su análisis de componentes:
@ComponentScan(excludeFilters = @Filter(IgnoreDuringScan.class)) public class MySpringConfiguration {}
fuente
@Component
, pero no creo que eso sea lo que pregunta la preguntaOtro enfoque consiste en utilizar nuevas anotaciones condicionales. Desde simple Spring 4, puede usar la anotación @Conditional:
@Component("foo") @Conditional(FooCondition.class) class Foo { ... }
y definir la lógica condicional para registrar el componente Foo:
public class FooCondition implements Condition{ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // return [your conditional logic] } }
La lógica condicional puede basarse en el contexto, porque tiene acceso a la fábrica de frijoles. Por ejemplo, cuando el componente "Bar" no está registrado como bean:
return !context.getBeanFactory().containsBean(Bar.class.getSimpleName());
Con Spring Boot (debe usarse para CADA nuevo proyecto de Spring), puede usar estas anotaciones condicionales:
@ConditionalOnBean
@ConditionalOnClass
@ConditionalOnExpression
@ConditionalOnJava
@ConditionalOnMissingBean
@ConditionalOnMissingClass
@ConditionalOnNotWebApplication
@ConditionalOnProperty
@ConditionalOnResource
@ConditionalOnWebApplication
Puede evitar la creación de clases de condición de esta manera. Consulte los documentos de Spring Boot para obtener más detalles.
fuente
En caso de que necesite definir dos o más criterios excludeFilters , debe usar la matriz.
Para los casos en esta sección de código, quiero excluir todas las clases en el paquete org.xxx.yyy y otra clase específica, MyClassToExclude
@ComponentScan( excludeFilters = { @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.xxx.yyy.*"), @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MyClassToExclude.class) })
fuente
Tuve un problema al usar @Configuration , @EnableAutoConfiguration y @ComponentScan mientras intentaba excluir clases de configuración específicas, ¡el problema es que no funcionó!
Eventualmente resolví el problema usando @SpringBootApplication , que según la documentación de Spring hace la misma funcionalidad que las tres anteriores en una anotación.
Otro consejo es intentar primero sin refinar el escaneo de paquetes (sin el filtro de paquetes base).
@SpringBootApplication(exclude= {Foo.class}) public class MySpringConfiguration {}
fuente
En caso de excluir el componente de prueba o la configuración de prueba, Spring Boot 1.4 introdujo nuevas anotaciones de prueba
@TestComponent
y@TestConfiguration
.fuente
Necesitaba excluir un @Aspect @Component de auditoría del contexto de la aplicación, pero solo para algunas clases de prueba. Terminé usando @Profile ("auditoría") en la clase de aspecto; incluyendo el perfil para operaciones normales pero excluyéndolo (no lo ponga en @ActiveProfiles) en las clases de prueba específicas.
fuente