如何将豆子注入春季条件类?



我正在定义条件,稍后我将检查这些条件以动态加载服务接口的两个实现之一。

@Component
public class IsPolicyEnabled implements Condition {
@Autowired
private MyProperties props;
@Override
public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) {
return props.isPolicyEnabled();
}
}

@Component
public class MyProperties {...}

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

但是,我遇到了运行时错误。

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)

基本上,它无法初始化在条件实现中自动连接的 props 对象。这是不允许的吗?

如何在条件实现中自动连接另一个依赖项,因为我的条件评估依赖于该依赖项提供的值?

注册 bean 定义之前立即检查条件 [...]

Condition, Spring Framework 5.0.8.RELEASE API 文档

您不能将 Bean 注入Condition实例中,因为上下文中还没有 Bean 定义1

此外,您不应该在Condition类中使用 bean:

条件必须遵循与BeanFactoryPostProcessor相同的限制,并注意永远不要与 Bean 实例交互

Condition, Spring Framework 5.0.8.RELEASE API 文档

您应该重新考虑设计,因为

[...]我的条件评估取决于该依赖关系提供的值。

表示不太对劲。

1准确地说,春天已经注册了一些豆子来满足自己的需要。

有两个问题:

1( 条件类没有注入

解决方案是从 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( 条件初始化发生得很早

尝试从 ConditionContext 检索 bean 失败并显示NoSuchBeanDefinitionException: No qualifying bean of type ...,因为条件检查发生在 Spring 生命周期的早期。

一个解决方案是有两个 Spring 上下文:

  • 仅定义MyProperties的父上下文
  • 一个子上下文,它定义应用程序的其余部分,并将 parentContext 作为其父级

因此,当调用条件时,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

最新更新