2013-09-24 11 views
39

Mam komponent, który chcę wykluczyć z @ComponentScan w danym @Configuration:wykluczyć @Component z @ComponentScan

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

W przeciwnym razie, wydaje się kolidować z innej klasy w moim projekcie. Nie w pełni rozumiem kolizję, ale jeśli komentuję adnotację @Component, wszystko działa tak, jak chcę. Ale inne projekty, które polegają na tej bibliotece, oczekują, że ta klasa będzie zarządzana przez Spring, więc chcę ją pominąć tylko w moim projekcie.

Próbowałem za pomocą @ComponentScan.Filter:

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

ale nie wydaje się do pracy. Gdy próbuję za pomocą FilterType.ASSIGNABLE_TYPE, mam dziwny błąd o byciu w stanie załadować jakąś pozornie przypadkowy Klasa:

spowodowane: java.io.FileNotFoundException: class zasobu path [junit/framework/TestCase.class] nie może być otwarte, ponieważ nie istnieje

próbowałem też za pomocą type=FilterType.CUSTOM następująco:

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

Ale to nie wydaje się, aby wykluczyć ze skanowania składnik jak chcę.

Jak mogę to wykluczyć?

+0

Czy możesz zaakceptować odpowiedź, jeśli pracowałeś dla Ciebie? –

Odpowiedz

45

Konfiguracja wydają się w porządku, oprócz tego, że należy użyć excludeFilters zamiast excludes:

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

Niestety, wystąpił błąd związany z wycięciem i wklejeniem. Używam excludeFilters. Przyjrzę jeszcze raz, błąd, który mi to daje, jest naprawdę dziwny ... – ykaganovich

14

Innym podejściem jest użycie nowych adnotacji warunkowych. Od zwykły Wiosna 4 można użyć @Conditional adnotacji:

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

i zdefiniowanie logiki warunkowej rejestracji komponentu Foo:

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

Warunkowe logika może opierać się na kontekście, ponieważ masz dostęp do fabryka fasoli.Dla przykładu, gdy składnik „Bar” nie jest zarejestrowany jako Jaś Fasola:

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

ze sprężyną Boot (powinien być stosowany dla każdego nowego projektu wiosenne), można użyć tych warunkowych adnotacje:

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

Można uniknąć tworzenia klasy Warunek ten sposób. Więcej informacji można znaleźć w dokumencie Spring Boot docs.

+0

+1 dla warunków warunkowych, jest to o wiele czystszy sposób niż używanie filtrów. Nie mam nigdy filtrów do pracy tak konsekwentnie jak warunkowe ładowanie ziaren. – wondergoat77

26

Używanie typów jawnych w filtrach skanowania jest dla mnie brzydkie. Wierzę, bardziej eleganckie podejście do tworzenia własnego markera adnotacji:

public @interface IgnoreDuringScan { 
} 

komponent Mark, które powinny być wyłączone z nim:

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

i uwzględniają tej adnotacji z komponentu skanowania:

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

To sprytny pomysł na uniwersalne wykluczenie, ale nie pomoże, jeśli chcesz wykluczyć komponent tylko z podzbioru kontekstów aplikacji w projekcie. Naprawdę, aby wykluczyć to powszechnie, można po prostu usunąć "@ Component", ale nie sądzę, że to pytanie zadaje – Kirby

3

Jeśli musisz zdefiniować dwa lub więcej kryteriów: excludeFilters, musisz użyć tablicy.

Dla instancji w tej części kodu chcę, aby wykluczyć wszelkie zajęcia w org.xxx.yyy pakietu i innej określonej klasy, MyClassToExclude

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

miałem problem przy korzystaniu @Configuration, @EnableAutoConfiguration i @ComponentScan podczas próby wykluczenia określonych klas konfiguracji, chodzi o to, że to nie zadziałało!

Ostatecznie rozwiązałem problem za pomocą @SpringBootApplication, który zgodnie z dokumentacją Spring ma tę samą funkcjonalność co trzy powyższe w jednej adnotacji.

Kolejną wskazówką jest wypróbowanie najpierw bez udoskonalania skanowania przesyłki (bez filtra basePackages).

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