私はこのスプリング構成を持っています:
@Lazy
@Configuration
public class MyAppConfig {
@Foo @Bean
public IFooService service1() { return new SpecialFooServiceImpl(); }
}
@Foo
アノテーションが付けられたすべてのBeanのリストを取得するにはどうすればよいですか?
注:@Foo
は、私が定義したカスタムアノテーションです。これは「公式の」Spring注釈の1つではありません。
[EDIT] Avinash T.の提案に従って、このテストケースを作成しました。
import static org.junit.Assert.*;
import Java.lang.annotation.ElementType;
import Java.lang.annotation.RetentionPolicy;
import Java.lang.annotation.Target;
import Java.lang.annotation.Retention;
import Java.lang.reflect.Method;
import Java.util.Map;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
public class CustomAnnotationsTest {
@Test
public void testFindByAnnotation() throws Exception {
AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext( CustomAnnotationsSpringCfg.class );
Method m = CustomAnnotationsSpringCfg.class.getMethod( "a" );
assertNotNull( m );
assertNotNull( m.getAnnotation( Foo.class ) );
BeanDefinition bdf = appContext.getBeanFactory().getBeanDefinition( "a" );
// Is there a way to list all annotations of bdf?
Map<String, Object> beans = appContext.getBeansWithAnnotation( Foo.class );
assertEquals( "[a]", beans.keySet().toString() );
}
@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.METHOD )
public static @interface Foo {
}
public static class Named {
private final String name;
public Named( String name ) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
@Lazy
@Configuration
public static class CustomAnnotationsSpringCfg {
@Foo @Bean public Named a() { return new Named( "a" ); }
@Bean public Named b() { return new Named( "b" ); }
}
}
しかし、org.junit.ComparisonFailure: expected:<[[a]]> but was:<[[]]>
で失敗します。どうして?
数人のSpringエキスパートの助けを借りて、解決策を見つけました。source
のBeanDefinition
プロパティはAnnotatedTypeMetadata
になります。このインターフェイスにはメソッドgetAnnotationAttributes()
があり、これを使用してBeanメソッドの注釈を取得できます。
public List<String> getBeansWithAnnotation( Class<? extends Annotation> type, Predicate<Map<String, Object>> attributeFilter ) {
List<String> result = Lists.newArrayList();
ConfigurableListableBeanFactory factory = applicationContext.getBeanFactory();
for( String name : factory.getBeanDefinitionNames() ) {
BeanDefinition bd = factory.getBeanDefinition( name );
if( bd.getSource() instanceof AnnotatedTypeMetadata ) {
AnnotatedTypeMetadata metadata = (AnnotatedTypeMetadata) bd.getSource();
Map<String, Object> attributes = metadata.getAnnotationAttributes( type.getName() );
if( null == attributes ) {
continue;
}
if( attributeFilter.apply( attributes ) ) {
result.add( name );
}
}
}
return result;
}
getBeansWithAnnotation() メソッドを使用して、注釈付きのBeanを取得します。
Map<String,Object> beans = applicationContext.getBeansWithAnnotation(Foo.class);
ここ は同様の議論です。
受け入れられた答えと Grzegorzの答え にはallの場合に機能するアプローチが含まれていますが、私ははるかにシンプルな機能を見つけました最も一般的なケースでも同様です。
1)@Foo
でメタ注釈@Qualifier
:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Foo {
}
2)質問で説明されているように、@Foo
をファクトリメソッドに振りかけます。
@Foo @Bean
public IFooService service1() { return new SpecialFooServiceImpl(); }
ただし、型レベルでも機能します。
@Foo
@Component
public class EvenMoreSpecialFooServiceImpl { ... }
3)次に、タイプと作成方法に関係なく、@Foo
で修飾されたすべてのインスタンスを挿入します。
@Autowired
@Foo
List<Object> fooBeans;
fooBeans
には、@Foo
- annotatedメソッド(質問で必要な場合)によって生成された、または検出された@Foo
注釈付きクラスから作成されたすべてのインスタンスが含まれます。
必要に応じて、リストをタイプ別にさらにフィルタリングできます。
@Autowired
@Foo
List<SpecialFooServiceImpl> fooBeans;
良い点は、メソッド上の他の@Qualifier
(メタ)アノテーションや、型レベルの@Component
およびその他のアノテーションと干渉しないことです。また、ターゲットBeanに特定の名前やタイプを強制しません。
a
Beanに_@Foo
_アノテーションを付けるには、a()
メソッドに_@Foo
_を配置するだけでは不十分です。
Springコードのデバッグを開始する前に気付いていなかったので、org.springframework.beans.factory.support.DefaultListableBeanFactory.findAnnotationOnBean(String, Class<A>)
のブレークポイントがそれを理解するのに役立ちました。
もちろん、注釈をNamedクラスに移動した場合:
_ @Foo
public static class Named {
...
_
また、テストのマイナーな詳細(アノテーションターゲットなど)を修正しましたテストが動作します。
考え直した後、それは非常に自然です。 getBeansWithAnnotation()
が呼び出されると、Springが持つ唯一の情報はBeanです。 Beanはオブジェクトであり、オブジェクトにはクラスがあります。また、Springは追加情報を保存する必要はないようです。注釈付きのBeanを作成するために使用されたファクトリメソッドなど.
[〜#〜] edit [〜#〜]_@Bean
_メソッドの注釈を保存するよう要求する問題があります: https://jira.springsource.org/browse/SPR-5611
次の回避策により、「修正しない」としてクローズされました。
BeanPostProcessor
を使用するbeanName
を使用して、関連するBeanDefinition
を囲んでいるBeanFactory
から検索しますBeanDefinition
(_@Configuration
_ Bean)およびfactoryBeanName
(_@Bean
_名)のfactoryMethodName
を照会するMethod
を取得します