鉴于此代码:
public interface Service {}
@Component
@Qualifier("NotWanted")
public class NotWantedService implements Service {}
@Component
@Qualifier("Wanted")
public class WantedService implements Service {}
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(NotWantedService.class);
ctx.register(WantedService.class);
ctx.refresh()
我现在该怎么做:
ctx.getBean(Service.class)
只会获得@Qualifier("Wanted")
而不是@Qualifier("NotWanted")
的那个?我特别询问是否可以使用getBean
来执行此操作,而不是注入类,然后使用该类作为一种代理。
答案 0 :(得分:12)
您可以使用
BeanFactoryAnnotationUtils.qualifiedBeanOfType(ctx.getBeanFactory(), Service.class, "Wanted")
使用ctx.getBeanFactory()
而非ctx
本身非常重要,因为' qualifiedBeanOfType'方法只能为ConfigurableListenableBeanFactory解析限定符。
答案 1 :(得分:8)
通过ApplicationContext获取bean时,使用它不是@Qualifier
注释的目的。但由于某些原因你需要这样或类似的功能,我建议一个解决方法。
创建@Wanted
和@NotWanted
注释:
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD,
ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Wanted {
}
和
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD,
ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotWanted {
}
使用这些新注释注释您的bean类:
@Component
@NotWanted
public class NotWantedService implements Service {}
和
@Component
@Wanted
public class WantedService implements Service {}
然后你应该在有权访问ApplicationContext
的地方添加2个方法:
ApplicationContext applicationContext;
private <T> Collection<T> getBeansByTypeAndAnnotation(Class<T> clazz, Class<? extends Annotation> annotationType){
Map<String, T> typedBeans = applicationContext.getBeansOfType(clazz);
Map<String, Object> annotatedBeans = applicationContext.getBeansWithAnnotation(annotationType);
typedBeans.keySet().retainAll(annotatedBeans.keySet());
return typedBeans.values();
}
private <T> Optional<T> getBeanByTypeAndAnnotation(Class<T> clazz, Class<? extends Annotation> annotationType) {
Collection<T> beans = getBeansByTypeAndAnnotation(clazz, annotationType);
return beans.stream().findFirst();
}
现在您可以使用它们通过注释来获取bean或一个bean,并按以下方式输入:
Collection<Service> services = getBeansByTypeAndAnnotation(Service.class, Wanted.class);
或
Service service = getBeanByTypeAndAnnotation(Service.class, Wanted.class);
可能它不是处理问题的最佳方式。但是,由于我们无法通过限定符来获取ApplicationContext
的bean,并打开了“开箱即用”,这就是其中一种方法。
答案 2 :(得分:2)
如果你想从上下文中获取bean而不是注入,更好的方法是在@Component注释中定义bean名称并从上下文中按名称获取它。在大多数情况下,@ Qualifier用于注射。
答案 3 :(得分:2)
就我而言,我有两个合格的一级豆,例如
@Configuration
public class AConfig {
@Bean(name = "a")
public Hello hello1() {
return new Hello();
}
@Bean(name = "b")
public Hello hello2() {
return new Hello();
}
}
然后我可以通过以下方式获取特定的豆
ApplicationContext context = SpringApplication.run(AutoConfiguration.class);
var aHello = context.getBean("a", Hello.class);
var bHello = context.getBean("b", Hello.class);
这是最简单的方法。或者,您可以执行以下相同操作:
var aHello = context.getBeansOfType(Hello.class).getBean("a");
var bHello = context.getBeansOfType(Hello.class).getBean("b");
或者您也可以按照@Dmitry Ovchinnikov的话做:
BeanFactoryAnnotationUtils.qualifiedBeanOfType(ctx.getBeanFactory(), Service.class, "Wanted")
在这种情况下,ctx.getBeanFactory()
可以替换为context.getAutowireCapableBeanFactory()
。
答案 4 :(得分:1)
在Spring中执行此操作的最接近的规范方法是使用实用程序类BeanFactoryAnnotationUtils ...但遗憾的是这只能直接使用@Qualifier
注释值参数(因此参数为字符串的原因)。
@Rozart is recommending是最好的方法,BeanFactoryAnnotationUtils
应该是这样的。在有人登陆并确实想直接使用@Qualifier
(以及随之附带的所有bean别名)的情况下,我只包含了上述答案。
我建议在春天提交一个功能请求(我会,但我认为他们可能会厌倦我嘲笑它们:-))。