我有这个弹簧配置:
@Lazy
@Configuration
public class MyAppConfig {
@Foo @Bean
public IFooService service1() { return new SpecialFooServiceImpl(); }
}
如何获取使用@Foo
注释的所有bean的列表?
注意:@Foo
是我定义的自定义注释。它不是“官方”Spring注释之一。
[编辑] 根据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:<[[]]>
失败了。为什么呢?
答案 0 :(得分:31)
使用getBeansWithAnnotation()方法获取带注释的bean。
Map<String,Object> beans = applicationContext.getBeansWithAnnotation(Foo.class);
Here也是类似的讨论。
答案 1 :(得分:22)
在几位Spring专家的帮助下,我找到了一个解决方案:source
的{{1}}属性可以是BeanDefinition
。这个接口有一个方法AnnotatedTypeMetadata
,我可以使用它来获取bean方法的注释:
getAnnotationAttributes()
答案 2 :(得分:13)
虽然接受的答案和Grzegorz's answer包含的方法可以在所有案例中使用,但我发现了一个更简单的方法,对于最常见的案例同样有效。
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
注释的方法生成的所有实例(根据问题的要求),或者从已发现的@Foo
带注释的类创建。
如果需要,可以按类型过滤列表:
@Autowired
@Foo
List<SpecialFooServiceImpl> fooBeans;
好的部分是它不会干扰方法上的任何其他@Qualifier
(元)注释,也不会干扰类型级别上的@Component
和其他注释。它也不会在目标bean上强制执行任何特定名称或类型。
答案 3 :(得分:12)
将@Foo
放在a()
方法上以使a
bean使用@Foo
进行注释是不够的。
在我开始调试Spring代码之前我没有意识到,org.springframework.beans.factory.support.DefaultListableBeanFactory.findAnnotationOnBean(String, Class<A>)
的断点帮助我理解它。
当然,如果您将注释移动到命名类:
@Foo
public static class Named {
...
并修复了测试的一些小细节(注释目标等)测试工作。
经过深思熟虑之后,这很自然。调用getBeansWithAnnotation()
时,Spring拥有的唯一信息就是bean。而bean是对象,对象有类。 Spring似乎不需要存储任何其他信息,包括。什么是用于创建带注释的bean的工厂方法等。
编辑有一个问题要求保留@Bean
方法的注释:https://jira.springsource.org/browse/SPR-5611
它已被关闭为“无法解决”以下解决方法:
BeanPostProcessor
beanName
从封闭的BeanDefinition
BeanFactory
BeanDefinition
factoryBeanName
(@Configuration
bean)和factoryMethodName
(@Bean
名称)Method
来自答案 4 :(得分:-1)
这是您如何注释的豆子
getAll(): Observable<IDataFromServer[]> {
return
this.http.get<IDataFromServer[]>('/api/rest')
.pipe(
tap(data => this.dataFromServer.next(data))
);
}