exclure @Component de @ComponentScan

J’ai un composant que je veux exclure d’un @ComponentScan dans un @Configuration particulier:

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

Sinon, cela semble entrer en conflit avec une autre classe de mon projet. Je ne comprends pas bien la collision, mais si je commente l’annotation @Component , les choses fonctionnent comme je le souhaite. Mais d’autres projets qui s’appuient sur cette bibliothèque s’attendent à ce que cette classe soit gérée par Spring, donc je veux l’ignorer uniquement dans mon projet.

J’ai essayé d’utiliser @ComponentScan.Filter :

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

mais cela ne semble pas fonctionner. Si j’essaie d’utiliser FilterType.ASSIGNABLE_TYPE , j’obtiens une erreur étrange à propos de l’impossibilité de charger une classe apparemment aléatoire:

Causée par: java.io.FileNotFoundException: la ressource de chemin de classe [junit / framework / TestCase.class] ne peut pas être ouverte car elle n’existe pas

J’ai également essayé d’utiliser le type=FilterType.CUSTOM comme suit:

 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 {} 

Mais cela ne semble pas exclure le composant du scan comme je le souhaite.

Comment puis-je l’exclure?

La configuration semble correcte, sauf que vous devez utiliser excludeFilters au lieu d’ excludes :

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

L’utilisation de types explicites dans les filtres d’parsing est moche pour moi. Je crois que l’approche plus élégante consiste à créer ses propres annotations de marqueur:

 public @interface IgnoreDuringScan { } 

Marquer le composant qui doit être exclu avec:

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

Et excluez cette annotation de l’parsing de vos composants:

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

Une autre approche consiste à utiliser de nouvelles annotations conditionnelles. Depuis plaine Spring 4, vous pouvez utiliser l’annotation @Conditional:

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

et définir la logique conditionnelle pour enregistrer le composant Foo:

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

La logique conditionnelle peut être basée sur le contexte, car vous avez access à la fabrique de beans. Par exemple, lorsque le composant “Bar” n’est pas enregistré en tant que bean:

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

Avec Spring Boot (doit être utilisé pour chaque nouveau projet Spring), vous pouvez utiliser ces annotations conditionnelles:

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

Vous pouvez éviter la création de classe de conditions de cette façon. Reportez-vous à la documentation de Spring Boot pour plus de détails.

Si vous devez définir deux critères d’ inclusionFilters ou plus, vous devez utiliser le tableau.

Pour les instances de cette section de code, je veux exclure toutes les classes du package org.xxx.yyy et une autre classe spécifique, MyClassToExclude

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

J’ai eu un problème lors de l’utilisation de @Configuration , @EnableAutoConfiguration et @ComponentScan en essayant d’exclure des classes de configuration spécifiques, le problème est que cela n’a pas fonctionné!

Finalement, j’ai résolu le problème en utilisant @SpringBootApplication , qui, selon la documentation de Spring, fait la même fonctionnalité que les trois précédentes dans une annotation.

Un autre conseil est d’essayer d’abord sans affiner l’parsing de votre paquet (sans le filtre basePackages).

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

En cas d’exclusion du composant de test ou de la configuration de test, Spring Boot 1.4 a introduit de nouvelles annotations de test @TestComponent et @TestConfiguration .

Je devais exclure un audit @Aspect @Component du contexte de l’application, mais seulement pour quelques classes de test. J’ai fini par utiliser @Profile (“audit”) sur la classe d’aspect; y compris le profil pour les opérations normales mais en l’excluant (ne le mettez pas dans @ActiveProfiles) sur les classes de test spécifiques.