Spring:Autowire bean没有限定符

时间:2017-06-17 17:31:29

标签: java spring dependency-injection

是否可以在春天自动装配没有给定限定符的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应包含Bean1Bean2但不包含Bean3的实例。

(注意:我知道相反的方法可行,即向Bean1Bean2添加一些限定符,然后使用该限定符进行自动装配。)

编辑:进一步澄清:

  • 所有bean都在spring环境中(也是被排除的bean)。
  • 配置需要基于注释,而不是基于xml。因此,例如关闭autowired-candidate does not work
  • bean的自动装配功能必须保持一般。换句话说,我想从注入点List<SomeBean> someBeanList;中排除bean,但我想在其他地方自动装配它。

3 个答案:

答案 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"

来排除bean成为自动装配的候选者

答案 1 :(得分:1)

可能有两种情况:

案例1:Bean3不在Spring环境中;

案例2:Bean3处于弹簧环境中,但在某些情况下没有注入@Autowired,

  1. 如果您需要从上下文中排除带有限定符的bean,请使用

    • 条件。如果匹配返回false,则此bean未在应用程序conxtet中注册。结果:
      

    @Autowired列出someBeanList; - 这里注入了所有bean的实例SomeBean并在应用程序上下文中注册。

    来自spring api

      

    条件为了a而必须匹配的单个条件   要注册的组件。之前立即检查条件   bean定义将被注册并可以自由否决   根据可以确定的任何标准进行注册   点。

  2. 使用限定符自动装配:

    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。

  3. 来自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
}