是否可以在春天自动装配没有给定限定符的bean?用例是拥有所有bean的列表,但不包括一个:
@Autowired
@NotQualifier("excludedBean") // <-- can we do something like this?
List<SomeBean> someBeanList;
public class Bean1 implements SomeBean {}
public class Bean2 implements SomeBean {}
@Qualifier("excludedBean")
public class Bean3 implements SomeBean {}
在上面的示例中,someList
应包含Bean1
和Bean2
但不包含Bean3
的实例。
(注意:我知道相反的方法可行,即向Bean1
和Bean2
添加一些限定符,然后使用该限定符进行自动装配。)
编辑:进一步澄清:
List<SomeBean> someBeanList;
中排除bean,但我想在其他地方自动装配它。答案 0 :(得分:4)
您可以使用元注释@Conditional
和@Qualifier
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
@Conditional(MyCondition.class)
public @interface ExcludeBean {
然后介绍可以执行条件逻辑的类
public class MyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !metadata.equals(ExcludeBean.class);
}
}
在您的配置类
中 @Bean
@ExcludeBean
public BeanA beanA() {
return new BeanA();
}
您还可以通过在特定bean上设置autowire-candidate
或指定default-autowire-candidates="list of candidates here"
答案 1 :(得分:1)
可能有两种情况:
案例1:Bean3不在Spring环境中;
案例2:Bean3处于弹簧环境中,但在某些情况下没有注入@Autowired,
如果您需要从上下文中排除带有限定符的bean,请使用
@Autowired列出someBeanList; - 这里注入了所有bean的实例SomeBean并在应用程序上下文中注册。
条件为了a而必须匹配的单个条件 要注册的组件。之前立即检查条件 bean定义将被注册并可以自由否决 根据可以确定的任何标准进行注册 点。
使用限定符自动装配:
2.1如果要使用autowired中的某个限定符排除bean 您可以使用的某些bean / beans和xml配置中的值 autowire-candidate
2.2你也可以得到 Setter Injection和仅过滤器的所有自动装配值 你需要的豆子。
//no Autowired. Autowired in method
private List<ParentBean> someBeen = new ArrayList<>();
@Autowired
public void setSomeBeen(List<ParentBean> beens){
// if you use java 8 use stream api
for (ParentBean bean:beens) {
Qualifier qualifier = bean.getClass().getAnnotation(Qualifier.class);
if(qualifier == null ||!qualifier.value().equals("excludedBean")){
someBeen.add(bean);
}
}
}
2.3如果您需要真正定制的内容,您可以使用custome AutowiredAnnotationBeanPostProcessor :)并自定义@Autowired。
来自spring api AutowiredAnnotationBeanPostProcessor:
注意:默认的AutowiredAnnotationBeanPostProcessor将是 由“context:annotation-config”注册 “context:component-scan”XML标签。删除或关闭默认值 如果您打算指定自定义,那么注释配置 AutowiredAnnotationBeanPostProcessor bean定义。
答案 2 :(得分:1)
主要观点它的排除bean是在上下文中但未注入某些具有排除条件的情况。
你可以使用带有自定义注释和BeanPostProcessor的限定符来排除bean。 (我为简单的例子做了例子,对于bean类型的集合,但你可以扩展它)
排除注释:
@Component
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcludeBeanByQualifierForCollectionAutowired {
String qualifierToExcludeValue();
Class<?> aClass();
}
带注入的bean后处理器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
@Component
public class ExcludeAutowiredBeanPostProcessor implements BeanPostProcessor {
@Autowired
private ConfigurableListableBeanFactory configurableBeanFactory;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
ExcludeBeanByQualifierForCollectionAutowired myAutowiredExcludeAnnotation = field.getAnnotation(ExcludeBeanByQualifierForCollectionAutowired.class);
if (myAutowiredExcludeAnnotation != null) {
Collection beanForInjection = new ArrayList<>();
String[] beanNamesOfType = configurableBeanFactory.getBeanNamesForType(myAutowiredExcludeAnnotation.aClass());
for (String injectedCandidateBeanName : beanNamesOfType) {
Object beanCandidate = configurableBeanFactory.getBean(injectedCandidateBeanName);
Qualifier qualifierForBeanCandidate = beanCandidate.getClass().getDeclaredAnnotation(Qualifier.class);
if (qualifierForBeanCandidate == null || !qualifierForBeanCandidate.value().equals(myAutowiredExcludeAnnotation.qualifierToExcludeValue())) {
beanForInjection.add(bean);
}
}
try {
field.set(bean, beanForInjection);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
和示例:
public class ParentBean {}
public class Bean1Included extends ParentBean {}
public class Bean2Included extends ParentBean {}
public class Bean3Included extends ParentBean {}
@Qualifier("excludedBean")
public class BeanExcluded extends ParentBean {}
构造
@Configuration
public class ConfigurationBean {
@Bean
public Bean1Included getBean1(){
return new Bean1Included();
}
@Bean
public Bean2Included getBean2(){
return new Bean2Included();
}
@Bean
public Bean3Included getBean3(){
return new Bean3Included();
}
@Bean
public BeanExcluded getExcludedBean(){
return new BeanExcluded();
}
@Bean
public ExcludeAutowiredBeanPostProcessor excludeAutowiredBeanPostProcessor(){
return new ExcludeAutowiredBeanPostProcessor();
}
}
和结果:
@ContextConfiguration(classes = ConfigurationBean.class)
public class ConditionTest {
@Autowired
private ApplicationContext context;
@Autowired
private BeanExcluded beanExcluded;
@ExcludeBeanByQualifierForCollectionAutowired(qualifierToExcludeValue = "excludedBean" , aClass = ParentBean.class)
private List<ParentBean> beensWithoutExclude;
context.getBeanNamesForType(ParentBean.class);//returns all sub type for ParentBean
beensWithoutExclude; // only bean1 ,bean2 , bean3 and NOT beanExcluded
beanExcluded;//been in application context
}