[英]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 documentationCondition
,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 documentationCondition
,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 上下文:
MyProperties
MyProperties
parentContext 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.