【问题标题】:Can @Inject be made optional in JSR 330 (like @Autowire(required=false)?可以在 JSR 330 中将 @Inject 设为可选(如 @Autowire(required=false) 吗?
【发布时间】:2013-10-29 10:26:26
【问题描述】:

可以配置 Spring 的 @Autowire,以便在找不到匹配的自动装配候选者时 Spring 不会抛出错误:@Autowire(required=false)

是否有等效的 JSR-330 注释?如果没有匹配的候选人,@Inject 总是失败。有什么方法可以使用@Inject,但如果找不到匹配的类型,框架不会失败?我还没有找到这种程度的任何文档。

【问题讨论】:

  • 真的不是一个好主意:他们选择在 CDI 中执行以确保所有依赖项都存在。你真的应该对依赖项进行空检查吗?似乎是一个架构问题,一些解决方案可能是注入一个接口,该接口可能具有无操作实现。 Null if not found 是非常糟糕的设计:是不是故意的,还是因为编程错误?

标签: java spring dependency-injection cdi


【解决方案1】:

不...在 JSR 330 中没有可选的等效项...如果您想使用可选注入,则必须坚持使用特定于框架的 @Autowired 注释

【讨论】:

【解决方案2】:

AutowiredAnnotationBeanFactoryPostProcessor (Spring 3.2) 包含此方法以确定是否需要支持的“Autowire”注释:

    /**
     * Determine if the annotated field or method requires its dependency.
     * <p>A 'required' dependency means that autowiring should fail when no beans
     * are found. Otherwise, the autowiring process will simply bypass the field
     * or method when no beans are found.
     * @param annotation the Autowired annotation
     * @return whether the annotation indicates that a dependency is required
     */
    protected boolean determineRequiredStatus(Annotation annotation) {
        try {
            Method method = ReflectionUtils.findMethod(annotation.annotationType(), this.requiredParameterName);
            if (method == null) {
                // annotations like @Inject and @Value don't have a method (attribute) named "required"
                // -> default to required status
                return true;
            }
            return (this.requiredParameterValue == (Boolean) ReflectionUtils.invokeMethod(method, annotation));
        }
        catch (Exception ex) {
            // an exception was thrown during reflective invocation of the required attribute
            // -> default to required status
            return true;
        }
    }

简而言之,不,默认情况下不是。

默认查找的方法名是'required',它不是@Inject注解上的字段,因此method会是nulltrue会被返回。

您可以通过继承 BeanPostProcessor 并覆盖 determineRequiredStatus(Annotation) 方法来更改它以返回 true,或者更确切地说,一些“更智能”的东西。

【讨论】:

  • 或者实现你自己的@Optional行为。
  • @SotiriosDelimanolis 我认为实现我自己的@Optional 行为将包括这里创建我自己的 BeanPostProccessor 的建议,但这似乎有点矫枉过正。我觉得 JSR330 没有包含 @Optional 注释很遗憾。
  • @EricB。是的,这就是这样做的方式。
【解决方案3】:

可以创建一个可选的注入点!

您需要使用http://docs.jboss.org/weld/reference/latest/en-US/html/injection.html#lookup 中记录的注入查找

@Inject
Instance<Type> instance;

// In the code
try {
   instance.get();
}catch (Exception e){

}

甚至是一个类型的所有实例

@Inject
Instance<List<Type>> instances

如果你需要的话,get() 方法也是惰性求值的。默认注入在启动时进行评估,如果没有找到可以注入的 bean,则抛出异常,当然,bean 将在运行时注入,但如果不可能,应用程序将不会启动。 在文档中,您将找到更多示例,包括如何过滤注入的实例等等。

【讨论】:

  • 这仅适用于 Weld?
  • 不,这对于任何 CDI 实现都是如此。
  • 啊,好吧,当我们谈论 JSR-330 时,我想这将是 JSR-330 的解决方案。
  • 上下文和依赖注入与JSR-330不一样?我不这么认为。
  • 对于 JSR-330 解决方案,可以使用 javax.inject.Provider 来达到类似的效果。
【解决方案4】:

实例注入经常被忽视。它增加了很大的灵活性。在获取依赖项之前检查它的可用性。不满意的 get 将抛出一个昂贵的异常。使用:

@Inject
Instance<SomeType> instance;
SomeType instantiation;

if (!instance.isUnsatisfied()) {
    instantiation = instance.get();
}

您可以正常限制注入候选者:

@Inject
@SomeAnnotation
Instance<SomeType> instance;

【讨论】:

  • 查看乔瓦尼·席尔瓦的回答
  • 谢谢!我不知道javax.enterprise.inject.Instance 类。但它是什么 JSR/pkg 的一部分?它似乎不是 JSR-330 的一部分。这是 JEE6 特有的东西吗?
  • java.enterprise.inject.Instance 在 JSR 299:JavaTM EE 平台的上下文和依赖注入中指定。如标题所述,它仅适用于 JEE 平台。 JSR 330:Java 的依赖注入是一个更轻量级的规范,不依赖于 JEE 平台。遗憾的是,JSR 330 没有包含 JSR 299 的所有非 JEE 特定特性,例如 java.enterprise.inject.Instance。为什么这没有发生,我将留给其他人猜测。
【解决方案5】:

您可以使用java.util.Optional。 如果您使用 Java 8 并且您的 Spring 版本是4.1 或更高版本(请参阅here),而不是

@Autowired(required = false)
private SomeBean someBean;

您可以只使用 Java 8 附带的 java.util.Optional 类。像这样使用它:

@Inject
private Optional<SomeBean> someBean;

这个实例永远不会是null,你可以像这样使用它:

if (someBean.isPresent()) {
   // do your thing
}

通过这种方式,您还可以进行构造函数注入,其中一些 bean 是必需的,一些 bean 是可选的,提供了极大的灵活性。

注意:很遗憾,Spring 不支持 Guavacom.google.common.base.Optional(请参阅 here),因此此方法仅在您使用 Java 8(或更高版本)时才有效。

【讨论】:

  • 有趣的选项。当我最初发布问题时,我不在 Java8 上,但我喜欢这个原则。感谢您指出。我想从技术上讲,使用 JSR330 仍然没有真正的选择,但这是利用 J8 的优势来绕过它的一个很好的选择。
  • 我正在使用 Java 8 和 Spring 4.2.7,它就像一个魅力。但是规范是否说明了如何管理“可选”类型?顺便说一句,这是一个非常合理的实现。我喜欢。
  • 当然,很棒。正是我所需要的,而且比可选的 null bean 更干净。
  • 很好的答案!注解参数不是叫required吗?
  • 但是您应该知道,通常不鼓励使用java.util.Optional 作为字段。它甚至没有实现Serializable 接口。
【解决方案6】:

Spring 支持 @Nullable@Inject

@Inject
@Nullable
void setSomeBean(SomeBean someBean)

【讨论】:

    猜你喜欢
    • 2019-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多