繁体   English   中英

如何在 Spring @Condition class 中自动装配 bean

[英]How to autowire a bean inside a Spring @Condition class

我有一个接口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");
    }
}

现在我有一个监听器 class,它有这个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");
    }
}

这对我来说似乎是一种魅力。 无论我需要注入哪种实现 class,我只需从其相应的Condition class 返回true ,并从实现类的Condition rest 的条件 class 返回false

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

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

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

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

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

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

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

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

条件必须遵循与 BeanFactoryPostProcessor 相同的限制,并注意永远不要与 bean 实例交互。 要对与 @Configuration bean 交互的条件进行更细粒度的控制,请考虑实现 ConfigurationCondition 接口。

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

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

在此处查看此链接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.

我将使用配置 class 和@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类。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM