wake-up-neo.com

@Component von @ComponentScan ausschließen

Ich habe eine Komponente, die ich aus einem @ComponentScan in einem bestimmten @Configuration ausschließen möchte:

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

Ansonsten scheint es mit einer anderen Klasse in meinem Projekt zu kollidieren. Ich verstehe die Kollision nicht vollständig, aber wenn ich die Annotation @Component auskommentiere, funktionieren die Dinge so, wie ich es möchte. Bei anderen Projekten, die auf diese Bibliothek angewiesen sind, wird jedoch erwartet, dass diese Klasse von Spring verwaltet wird. Daher möchte ich sie nur in meinem Projekt überspringen.

Ich habe versucht, @ComponentScan.Filter zu verwenden:

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

aber es scheint nicht zu funktionieren. Wenn ich versuche, FilterType.ASSIGNABLE_TYPE zu verwenden, erhalte ich die seltsame Fehlermeldung, dass eine scheinbar zufällige Klasse nicht geladen werden kann:

Ursache: Java.io.FileNotFoundException: Die Klassenpfadressource [junit/framework/TestCase.class] kann nicht geöffnet werden, da sie nicht vorhanden ist

Ich habe auch versucht, type=FilterType.CUSTOM wie folgt zu verwenden:

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

Aber das scheint die Komponente nicht wie gewünscht vom Scan auszuschließen.

Wie kann ich das ausschließen?

57
ykaganovich

Die Konfiguration scheint in Ordnung zu sein, außer dass Sie excludeFilters anstelle von excludes verwenden sollten:

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

Die Verwendung expliziter Typen in Scanfiltern ist für mich hässlich. Ich glaube, ein eleganterer Ansatz ist das Erstellen eigener Markierungsanmerkungen:

public @interface IgnoreDuringScan {
}

Komponente markieren, die mit ausgeschlossen werden soll:

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

Und schließen Sie diese Anmerkung von Ihrem Komponentenscan aus:

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

Ein anderer Ansatz ist die Verwendung neuer bedingter Annotationen . Seit plain Spring 4 können Sie @Conditional-Annotation verwenden:

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

und definieren Sie eine bedingte Logik für die Registrierung der Foo-Komponente:

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

Bedingte Logik kann auf dem Kontext basieren, da Sie Zugriff auf die Bean-Factory haben. Zum Beispiel, wenn die Komponente "Bar" nicht als Bean registriert ist:

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

Mit Spring Boot (sollte für JEDES neue Spring-Projekt verwendet werden) können Sie diese bedingten Anmerkungen verwenden:

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

Sie können die Erstellung von Konditionsklassen auf diese Weise vermeiden. Weitere Informationen finden Sie unter Spring Boot-Dokumente.

20
luboskrnac

Wenn Sie zwei oder mehr excludeFilters -kriterien definieren müssen, müssen Sie das Array verwenden. 

Für Instanzen in diesem Abschnitt des Codes möchte ich alle Klassen im Paket org.xxx.yyy und eine andere bestimmte Klasse ausschließen, MyClassToExclude

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

Ich hatte ein Problem bei der Verwendung von @Configuration, @EnableAutoConfiguration und @ComponentScan, während ich versuchte, bestimmte Konfigurationsklassen auszuschließen. 

Irgendwann löste ich das Problem durch die Verwendung von @SpringBootApplication , die laut Spring-Dokumentation in einer Anmerkung die gleiche Funktionalität wie die drei oben genannten Funktionen aufweist.

Ein weiterer Tipp ist, zuerst den Paketscan zu verfeinern (ohne den basePackages-Filter).

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

Bei Ausschluss von Testkomponenten oder Testkonfigurationen wurden in Spring Boot 1.4 neue Testanmerkungen @TestComponent UND @TestConfiguration eingeführt.

1
luboskrnac

Ich musste ein Auditing @Aspect @Component aus dem App-Kontext ausschließen, jedoch nur für einige Testklassen. Am Ende habe ich @Profile ("audit") für die Aspektklasse verwendet. Einschließlich des Profils für normale Vorgänge, jedoch nicht (in @ActiveProfiles) für die spezifischen Testklassen.

0
Miguel Pereira