当前位置: 首页 > 知识库问答 >
问题:

Spring:没有限定符的自动连线豆

仲孙奇
2023-03-14

有可能在Spring自动连接没有给定限定符的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

(备注:我知道相反的效果,即向Bean1Bean2添加一些限定符,然后使用该限定符自动连接。)

编辑:一些进一步的澄清:

  • 所有豆子都在Spring环境中(也被排除在外)。
  • 配置需要基于注释,而不是基于 xml。因此,例如关闭自动连线候选不起作用。
  • 通常必须保持 Bean 的自动连线功能。换句话说,我想从注入点列表中排除豆子

共有3个答案

段干博涉
2023-03-14

可能有两种情况:

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

情况 2 : Bean3 在 Spring 上下文中,但在某些情况下没有注入 @Autowired,

>

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

      < li >条件。如果matches返回false,则此bean未在应用程序conxtet中注册。结果:

    @ Autowired List someBeanList-此处注入了SomeBean的所有Bean实例,并在应用程序上下文中注册。

    来自spring api

    条件注册组件时必须匹配的单个条件。在bean-definition将要注册之前,会立即检查条件,并且可以根据当时确定的任何标准自由否决注册。

    带限定符的自动连线:

    2.1如果您想从某些bean/bean和xml配置中的自动连接值中排除带有some限定符的bean,您可以使用autowire-candidate

    2.2还可以通过Setter Injection获取所有自动关联的值,并只过滤所需的bean。

    //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 您可以使用自定义自动连线注释BeanPostProcessor:)如果您需要一些真正的定制,请根据您的要求定制@Autowired。

    来自spring API AutowiredAnnotationBeanPostProcessor:

    注意:默认的AutowiredAnnotationBeanPostProcessor将由“context:annotationconfig”和“context:componentscan”XML标记注册。如果要指定自定义AutowiredAnnotationBeanPostProcessorbean定义,请删除或关闭默认注释配置。

  • 李弘光
    2023-03-14

    要点它的bean for exclude在上下文中,但没有注入到某些带有exclude条件的情况中。

    您可以使用自定义annotaion和BeanPostProcessor排除带有限定符的bean。(我是以简单的bean类型集合为例,但是您可以扩展它)

    排除的注释:

    @Component
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ExcludeBeanByQualifierForCollectionAutowired {
    
        String qualifierToExcludeValue();
    
        Class<?> aClass();
    }
    

    带注射的豆后处理器

    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<Object> 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(beanCandidate);
                        }
                    }
                    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 BeanConfiguration {
    
        @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();
        }
    }
    

    和结果:

    @ExtendWith(SpringExtension.class) // assumes Junit 5
    @ContextConfiguration(classes = BeanConfiguration.class)
    public class ExcludeConditionTest {
    
        @Autowired
        private ApplicationContext context;
        @Autowired
        private BeanExcluded beanExcluded;
        @ExcludeBeanByQualifierForCollectionAutowired(qualifierToExcludeValue = "excludedBean" , aClass = ParentBean.class)
        private List<ParentBean> beensWithoutExclude;
    
        @Test
        void should_not_inject_excluded_bean() {
            assertThat(context.getBeansOfType(ParentBean.class).values())
                    .hasOnlyElementsOfTypes(Bean1Included.class,
                                            Bean2Included.class,
                                            Bean3Included.class,
                                            BeanExcluded.class);
    
            assertThat(beansWithoutExclude)
                    .hasOnlyElementsOfTypes(Bean1Included.class,
                                            Bean2Included.class,
                                            Bean3Included.class)
                    .doesNotHaveAnyElementsOfTypes(BeanExcluded.class);
    
            assertThat(beanExcluded).isNotNull();
        }
    }
    
    岳阳飙
    2023-03-14

    您可以使用元注解@条件@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或指定defaultautowirecandidates=“listofcandidatehere”来将bean排除为自动布线的候选对象

     类似资料:
    • 我对从类扩展的Spring bean初始化有一个问题。我完全卡住了。 类hiearchy如下所示: 提到该类对需要初始化的服务很有用: 创建bean时: 则中的为null-似乎没有自动连线。 它能否与是从抽象类扩展而来的这一事实相联系? 这个bean可能从未初始化过... 这是个例外: org.springframework.beans.factory.UnsatisfiedDependencyE

    • 我有个小问题。如果类是用@component、@service、@controller或@repository注释的,并且我想注入它的依赖项,我需要@autowired吗? 这段代码对我来说非常适用,因为它是UserDeviceService中指定的@Service注释。是因为那个吗?

    • 我有一个带有自动扫描和@Component注释的Spring项目。一些组件需要使用@Autow的注入到不同的bean中。默认情况下,它是否将是作为单例创建的相同组件bean?如果是,如何将同一组件的不同实例注入不同的bean中? 附言:我知道它接近基础,听起来很一般。只是想自己说清楚。 提前致谢

    • 那么我的问题是,@javax为什么会这样做。注释。资源工作,但@AutoWired没有工作。为了在Restful控制器上进行测试,我尝试将MappingJackson2HttpMessageConverter注入@Autowired,在启动时,容器未能找到符合条件的bean,即使该类位于路径上。现在,为了解决这个问题,我进入了一个上下文xml文件并添加了bean: 然后在测试类中有成员变量: 然后

    • 我定义了一个简单的类来保存我的elasticsearch客户端(称为ElasticClientConfig.java)的配置属性。 我为我的开发、生产和测试环境定义了一个配置。每个配置概要文件都有一个方法,该方法返回ElasticClientConfig类型的bean,并使用特定于环境的参数构建一个MyConfig对象。以下是开发版本: 我在我的网站中将我的活动配置文件设置为“dev”。xml文件

    • 我的问题是:我有一个基本接口和两个实现类。 服务类依赖于基本接口,代码如下: 而配置是这样的: 服务类依赖于基础接口,将决定通过某些业务逻辑自动连接哪个实现。代码是这样的: 这个想法引发了一个例外:无法自动连线。有多个bean属于类型。 虽然可以使用@Qualifier来解决这个问题,但在这种情况下,我不能选择dependencies类。 我试图阅读spring文档,它提供了一个基于,但我仍然对这

    • 问题内容: 我在Spring定义了这样的地图: 然后,我将该bean自动装配为定义为的属性: 这样做时,会抛出一个异常,说: `Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘DutyCreator’: Injection of autowired

    • 我对spring中的@Autowired注释有问题。我有一个RestController类: 接口: CategoryManagerImpl类: 每次编译代码时,我都会遇到一个异常: Bun当我创建ApplicationContext并尝试获取categoryManagerImpl bean时,没有问题: 有人知道哪里会有问题吗? 谢谢 添加了 配置类: 堆栈跟踪: