exclure @Component de @ComponentScan


90

J'ai un composant que je souhaite exclure d'un @ComponentScandans un particulier @Configuration:

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

Sinon, il semble entrer en conflit avec une autre classe de mon projet. Je ne comprends pas entièrement la collision, mais si je commente l' @Componentannotation, les choses fonctionnent comme je le souhaite. Mais d'autres projets qui reposent 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'essaye d'utiliser FilterType.ASSIGNABLE_TYPE, j'obtiens une erreur étrange concernant 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 type=FilterType.CUSTOMcomme 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 de l'analyse comme je le souhaite.

Comment l'exclure?

Réponses:


107

La configuration semble correcte, sauf que vous devriez utiliser à la excludeFiltersplace de excludes:

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

désolé, c'était une erreur de copier-coller. J'utilise excludeFilters. Je vais jeter un autre regard, l'erreur que cela me donne est vraiment bizarre ...
— ykaganovich

52

L'utilisation de types explicites dans les filtres d'analyse est moche pour moi. Je pense qu'une approche plus élégante consiste à créer sa propre annotation de marqueur:

@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreDuringScan {
}

Marquer le composant à exclure avec lui:

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

Et excluez cette annotation de l'analyse de vos composants:

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

13
C'est une idée intelligente d'exclusion universelle, mais ne vous aidera pas si vous souhaitez exclure un composant d'un sous-ensemble de contextes d'application dans un projet. Vraiment, pour l'exclure universellement, on pourrait simplement supprimer le @Component, mais je ne pense pas que ce soit ce que la question pose
— Kirby

2
cela ne fonctionnera pas si vous avez une autre annotation d'analyse de composant quelque part qui n'a pas le même filtre
— Bashar Ali Labadi

@Bashar Ali Labadi, n'est-ce pas ce genre de point de cette construction? Si vous souhaitez l'exclure de toutes les analyses de composants, il ne devrait probablement pas s'agir d'un composant Spring.
— luboskrnac

30

Une autre approche consiste à utiliser de nouvelles annotations conditionnelles. Depuis plain Spring 4, vous pouvez utiliser l'annotation @Conditionnelle:

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

et définissez une logique conditionnelle pour l'enregistrement du 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 accès à la fabrique de bean. Par exemple, lorsque le composant "Bar" n'est pas enregistré comme bean:

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

Avec Spring Boot (devrait ê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 Condition de cette façon. Reportez-vous à la documentation de Spring Boot pour plus de détails.


1
+1 pour les conditions, c'est une façon beaucoup plus propre que d'utiliser des filtres. Je n'ai jamais fait fonctionner les filtres aussi régulièrement que le chargement conditionnel de haricots
— wonderergoat77

13

Si vous devez définir deux ou plusieurs critères excludeFilters , vous devez utiliser le tableau.

Pour les instances de cette section de code, je souhaite 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) })

Je suggérerais ASPECTJ comme type de filtre, car cette expression régulière correspondrait également à "org.xxx.yyyy.z"
— wutzebaer

9

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, offre les mêmes fonctionnalités que les trois ci-dessus dans une annotation.

Une autre astuce consiste à essayer d'abord sans affiner l'analyse de votre package (sans le filtre basePackages).

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

J'ai essayé ceci mais affichant l'erreur comme "Les classes suivantes n'ont pas pu être exclues parce qu'elles ne sont pas des classes de configuration automatique". excludeFilters avec @ComponentScan fonctionne correctement.
— AzarEJ le


0

J'avais besoin d'exclure un audit @Aspect @Component du contexte de l'application, mais uniquement pour quelques classes de test. J'ai fini par utiliser @Profile ("audit") sur la classe d'aspect; en incluant le profil pour les opérations normales mais en l'excluant (ne le mettez pas dans @ActiveProfiles) sur les classes de test spécifiques.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.