web-dev-qa-db-ja.com

@ComponentScanから@Componentを除外する

特定の@ComponentScan@Configurationから除外したいコンポーネントがあります:

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

そうでなければ、私のプロジェクトの他のクラスと衝突するようです。衝突を完全には理解していませんが、@Component注釈をコメントアウトすると、期待どおりに動作します。しかし、このライブラリに依存する他のプロジェクトは、このクラスがSpringによって管理されることを想定しているため、自分のプロジェクトでのみこのクラスをスキップします。

@ComponentScan.Filterを使用してみました:

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

しかし、動作していないようです。 FilterType.ASSIGNABLE_TYPEを使用しようとすると、ランダムに見えるクラスをロードできないという奇妙なエラーが表示されます。

原因:Java.io.FileNotFoundException:クラスパスリソース[junit/framework/TestCase.class]は存在しないため開くことができません

また、次のようにtype=FilterType.CUSTOMを使用してみました:

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

しかし、それは私が望むようにスキャンからコンポーネントを除外するようには見えません。

除外するにはどうすればよいですか?

71
ykaganovich

excludeFiltersの代わりにexcludesを使用する必要があることを除いて、構成は問題ないように見えます。

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

スキャンフィルターで明示的な型を使用するのはmeいです。よりエレガントなアプローチは、独自のマーカー注釈を作成することです。

public @interface IgnoreDuringScan {
}

除外するコンポーネントにそれをマークします。

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

コンポーネントスキャンからこの注釈を除外します。

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

別のアプローチは、新しい条件付き注釈を使用することです。 plain Spring 4なので、@ Conditionalアノテーションを使用できます。

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

fooコンポーネントを登録するための条件ロジックを定義します。

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

Beanファクトリにアクセスできるため、条件ロジックはコンテキストに基づいて作成できます。たとえば、「Bar」コンポーネントがBeanとして登録されていない場合:

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

Spring Boot(すべての新しいSpringプロジェクトに使用する必要があります)では、これらの条件付き注釈を使用できます:

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

この方法で条件クラスの作成を回避できます。詳細については、Spring Bootのドキュメントを参照してください。

22
luboskrnac

2つ以上のexcludeFilters基準を定義する必要がある場合は、配列を使用する必要があります。

このコードセクションのインスタンスでは、org.xxx.yyyパッケージと別の特定のクラスMyClassToExcludeのすべてのクラスを除外します

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

@ Configuration@ EnableAutoConfigurationおよび@ ComponentScan特定の構成クラスを除外しようとしても、うまくいかなかったのです!

最終的に、私は @ SpringBootApplication を使用して問題を解決しました。注釈。

もう1つのヒントは、パッケージスキャンを調整せずに(basePackagesフィルターなしで)最初に試すことです。

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

テストコンポーネントまたはテスト構成を除外する場合、Spring Boot 1.4は新しいテストアノテーション @TestComponentおよび@TestConfiguration を導入しました。

1
luboskrnac

アプリコンテキストから監査@Aspect @Componentを除外する必要がありましたが、いくつかのテストクラスについてのみです。アスペクトクラスで@Profile( "audit")を使用することになりました。特定のテストクラスで通常の操作のプロファイルを含めますが、それを除外します(@ActiveProfilesに入れないでください)。

0
Miguel Pereira