【问题标题】:How to autowire a bean inside a Spring @Condition class如何在 Spring @Condition 类中自动装配 bean
【发布时间】:2022-08-20 03:04:35
【问题描述】:

我有一个界面IInterface.java,如下所示:

public interface IInterface {
    void printIt();
}

为此有两个实现类:ImplementationA.javaImplementationB.java

@Component
public class ImplementationA implements IInterface {
    @Override
    public void printIt() {
        System.out.println(\"Inside ImplementationA\");
    }
}

@Component
public class ImplementationB implements IInterface {
    @Override
    public void printIt() {
        System.out.println(\"Inside ImplementationB\");
    }
}

现在我有一个监听器类,它有这个IInterface 作为成员:

@Component
@AllArgsConstructor
public class Listener {

    IInterface iInterface;

    public void doStuff(){
        iInterface.printIt();
    }
}

现在,我的要求是根据特定条件在Listener.javaiInterface 成员中注入ImplementationA.javaImplementationB.java

经过一番研究,我开始使用@Conditional 注释。 我添加了两个类ConditionA.javaConditionB.java

public class ConditionA implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return false;
    }
}
public class ConditionB implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return true;
    }
}

而且我还改变了我的实现类如下(添加了Conditional注解):

@Component
@Conditional(ConditionA.class)
public class ImplementationA implements IInterface {
    @Override
    public void printIt() {
        System.out.println(\"Inside ImplementationA\");
    }
}

@Component
@Conditional(ConditionB.class)
public class ImplementationB implements IInterface {
    @Override
    public void printIt() {
        System.out.println(\"Inside ImplementationA\");
    }
}

这对我来说似乎是一种魅力。无论我需要注入哪个实现类,我只需从其对应的Condition 类返回true,并从实现类的Condition 类的其余部分返回false

然而,下一部分是我面临挑战的地方: 因此,从上述解决方案中,我从对应的Condition 类的matches 方法中对return truereturn false 进行了硬编码。如果我需要基于另一个组件返回一个动态值怎么办。

假设我有一个弹簧ComponentMyCustomConfig,它有一个成员customFlag,如果这个成员设置为true,我们需要注入ImplementationA.class。 我尝试了以下方法(创建了@Component 类并自动连接了 MyCustomConfig):

@Component
public class ConditionA implements Condition {
    @Autowired
    MyCustomConfig myCustomConfig;    

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return myCustomConfig.getCustomFlag();
    }
}

然而,这根本行不通。 myCustomConfig 不是自动装配的,我得到一个空指针异常。

有人可以帮我解决这个问题。

  • 你如何实例化你的 ConditionAL 类?
  • 我实际上并没有实例化 ConditionA.class。当我使用 @Conditional(ConditionA.class) 对我的 ImplementationA 类进行 annonate 时,Spring 似乎在内部执行此操作
  • 我实际上并没有在您的代码中看到这一点,也没有
  • @Stultuske 你没看到什么?
  • 为什么不通过实现 A 和 B 来实现 Condition 并在运行时使用策略来确定具体实例?

标签: java spring spring-boot spring-annotations spring5


【解决方案1】:

我认为使用implements Condition 没有机会满足您的需求。

如果您检查documentation 中的interface Condition,这是您提供给@Conditional 的类应该做的事情,在您的情况下ConditionAConditionB 它说:

条件必须遵循与 BeanFactory后处理器并注意不要与 bean 交互 实例。对相互作用的条件进行更细粒度的控制 使用 @Configuration bean 考虑实现 配置条件接口。

也许这个answer 会为您提供一种解决方法,正如上面在文档中提到的那样,如果您想干扰其他bean,您应该实现自己的自定义ConfigurationCondition。

只需检查此 ConfigurationCondition 将运行的阶段将在您需要的 bean 注册之后

【讨论】:

    【解决方案2】:

    我将使用配置类和@Bean 注册 bean,如下所示:

    @Configuration
    public class ImplementationConfig {
        @Bean 
        public IInterface implementation(MyCustomConfig myCustomConfig) {
            if (myCustomConfig.getCustomFlag()) {
               return new ImplementationA();
            } else {
               return new ImplementationB();
            }
        }
    }
    

    您只需在 ImplementationAImplementationB 中删除与 Spring 相关的注释:

    public class ImplementationA implements IInterface {
        @Override
        public void printIt() {
            System.out.println("Inside ImplementationA");
        }
    }
    
    public class ImplementationB implements IInterface {
        @Override
        public void printIt() {
            System.out.println("Inside ImplementationA");
        }
    }
    

    最后,您可以删除 Condition 类。

    【讨论】:

      【解决方案3】:

      在此处查看此链接https://stackoverflow.com/a/70351394/7237884

      文档说

      Conditions must follow the same restrictions as BeanFactoryPostProcessor and take care to never interact with bean instances. For more fine-grained control of conditions that interact with @Configuration beans consider implementing the ConfigurationCondition interface.
      

      【讨论】:

        猜你喜欢
        • 2015-04-17
        • 1970-01-01
        • 1970-01-01
        • 2022-01-24
        • 2019-02-03
        • 2022-09-23
        • 2020-11-19
        • 2012-08-11
        • 2014-03-11
        相关资源
        最近更新 更多