【问题标题】:Why CDI beans don't support final methods为什么 CDI bean 不支持 final 方法
【发布时间】:2014-01-08 00:55:11
【问题描述】:

我刚刚在 GlassFish 服务器下发生了臭名昭著的 JavaEE CDI 错误:

org.glassfish.deployment.common.DeploymentException: CDI deployment failure:Exception List with 2 exceptions:
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001437 Normal scoped bean class ASController is not proxyable because the type is final or it contains a final method public final void ASController.selectPath(org.primefaces.event.NodeSelectEvent) - Managed Bean [class ASController] with qualifiers [@Default @Any @Named].

这个错误非常明确,因为他不喜欢 CDI bean 中的 final 方法,但我不明白为什么。

在这个链接

http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html_single/#d0e1429

他们解释说这与序列化有关,但我不明白为什么用 final 方法序列化一个类应该比用非 final 方法更难。

【问题讨论】:

    标签: java jakarta-ee cdi


    【解决方案1】:

    嗯,有几种方法可以实现代理对象。但是由于您希望代理与代理 bean 具有“相同”类型,因此您必须使用继承(或您可以实现的需求接口,但这不是每个 POJO 都可以成为 bean 的方法CDI)。

    也就是说,它们从您要注入的类内部扩展,围绕它生成一些代理代码并为您提供该子类。

    然后这个代理会处理所有的魔法来确保你总是有一个适合你的上下文的 bean(并且这个 bean 的所有成员变量 beans 都指向正确的 bean)。

    因此,您实际上并没有收到要注入的 bean 的类型,而是该 bean 的代理子类。这不适用于 final 方法和类以及私有构造函数。

    如果类不是final,代理可以扩展这个类,但是它不能轻易覆盖你的final方法。然而,这可能是需要的(例如,如果您的 bean 被序列化,代理需要反序列化它)。

    还有更复杂的方法。可以通过代理操作类的字节码来注入此功能(例如,删除最终修饰符,注入默认构造函数,...)甚至可能将其与继承混合,但这还没有实现(和支持多个 JVM 实现也很重要)。

    来自链接资源的注释表明这是计划在未来发布的:

    注意

    Weld 的未来版本可能会支持非标准解决方法 对于这个限制,使用不可移植的 JVM API: Sun、IcedTea、Mac:Unsafe.allocateInstance()(最高效) IBM,JRockit:ReflectionFactory.newConstructorForSerialization()

    但我们还没有着手实施。

    【讨论】:

    • 现在明白了,另一个答案是正确的,但这个更详细。
    【解决方案2】:

    容器为注入的类创建代理对象。因此,容器不使用您的类,但这些类扩展。 Java 禁止扩展 final 类,所以不能在 CDI 中使用 final 类。

    【讨论】:

    • 我的类不是final的,它只是有一个final方法,所以CDI可以扩展它。
    • 问题一样,代理类会覆盖方法,但是如果它们最终代理不能覆盖它们
    猜你喜欢
    • 1970-01-01
    • 2013-03-03
    • 1970-01-01
    • 1970-01-01
    • 2013-09-05
    • 2013-03-09
    • 2012-12-02
    • 2012-03-11
    相关资源
    最近更新 更多