简体   繁体   English

如何将 bean 注入 Spring Condition 类?

[英]How to inject a bean into a Spring Condition class?

I am defining conditions that I will check to dynamically load one of the two implementations of my service interface later.我正在定义条件,稍后我将检查这些条件以动态加载我的服务接口的两个实现之一。

@Component
public class IsPolicyEnabled implements Condition {

    @Autowired
    private MyProperties props;

    @Override
    public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) {
        return props.isPolicyEnabled();
    }

}

And

@Component
public class MyProperties {...}

And

@Service
@Conditional(IsPolicyEnabled.class)
public class ServiceA implements Service {...}

However, I am running into a runtime error as.但是,我遇到了运行时错误。

java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: java.lang.NullPointerException
at com.xyz.utils.IsPolicyEnabled.matches(IsPolicyEnabled.java:9)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:88)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:71)
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.isConditionMatch(ClassPathScanningCandidateComponentProvider.java:515)

Basically, it failed to initialize props object that has been auto-wired inside the condition implementation.基本上,它无法初始化已在条件实现中自动连接的 props 对象。 Is that not allowed?这是不允许的吗?

How can I auto wire another dependency inside the condition implementation since my condition evaluation depends on a value provided by that dependency?我如何在条件实现中自动连接另一个依赖项,因为我的条件评估取决于该依赖项提供的值?

Conditions are checked immediately before the bean-definition is due to be registered [...]在注册 bean 定义之前立即检查条件 [...]

Condition , Spring Framework 5.0.8.RELEASE API documentation Condition ,Spring Framework 5.0.8.RELEASE API 文档

You can't inject a bean into a Condition instance because there are no bean-definitions in the context yet 1 .您不能将 bean 注入Condition实例,因为上下文中还没有 bean 定义1

Moreover, you are not supposed to work with beans within Condition classes:此外,您不应该在Condition类中使用 bean:

Conditions must follow the same restrictions as BeanFactoryPostProcessor and take care to never interact with bean instances .条件必须遵循与BeanFactoryPostProcessor相同的限制,并注意不要与 bean 实例交互

Condition , Spring Framework 5.0.8.RELEASE API documentation Condition ,Spring Framework 5.0.8.RELEASE API 文档

You should rethink the design because你应该重新考虑设计,因为

[...] my condition evaluation depends on a value provided by that dependency. [...] 我的条件评估取决于该依赖项提供的值。

indicates that it's not quite right.表示不太正确。

1 Precisely speaking, there are a few beans already registered by Spring for its own needs. 1准确地说,Spring已经为自己的需要注册了一些bean。

There are two issues:有两个问题:

1) There is no injection for Condition classes 1) Condition 类没有注入

Solution is to retrieve beans from ConditionContext:解决方案是从 ConditionContext 检索 bean:

@Component
public class IsPolicyEnabled implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        MyProperties props = context.getBeanFactory().getBean(MyProperties.class);

        return props.isPolicyEnabled();
    }
}

2) Condition initialization happens very early 2)条件初始化发生得非常早

Trying to retrieve beans from ConditionContext fails with NoSuchBeanDefinitionException: No qualifying bean of type ... because condition check happens very early in the Spring lifecycle.尝试从 ConditionContext 检索 bean 失败,出现NoSuchBeanDefinitionException: No qualifying bean of type ...因为条件检查发生在 Spring 生命周期的早期。

A solution is to have two Spring contexts:一个解决方案是有两个 Spring 上下文:

  • A parentContext which defines only MyProperties仅定义MyProperties parentContext
  • A childContext which defines the rest of the application and has parentContext as its parent定义应用程序的其余部分并将 parentContext 作为其父级的 childContext

So when the Condition is invoked, MyProperties is already created in the parent context:因此,当调用 Condition 时, MyProperties已经在父上下文中创建:

ApplicationContext parentContext = new AnnotationConfigApplicationContext(MyProperties.class);
ApplicationContext childContext = new AnnotationConfigApplicationContext();
childContext.setParent(parent);
childContext.register(ApplicationConfiguration.class);
childContext.refresh();

Service service = childContext.getBean(Service.class);
// do something with service

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

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