我刚刚在 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 方法更难。
最佳答案
好吧,有几种方法可以实现代理对象。但是由于您希望代理与被代理的 bean 具有“相同”的类型,因此您将不得不使用继承(或您随后可以实现的需求接口(interface),但这不是每个 POJO 都可以是一个 bean 的方法CDI)。
也就是说,它们从您要注入(inject)的类内部扩展,围绕它生成一些代理代码并为您提供该子类。
然后这个代理处理所有魔法以确保您始终有一个适合您的上下文的 bean(并且这个 bean 的所有成员变量 beans 都指向正确的 beans)。
因此,您实际上并没有收到要注入(inject)的 bean 的类型,而是该 bean 的代理子类。这不适用于 final方法和类以及私有(private)构造函数。
如果类不是final,代理可以扩展这个类,但是它不能轻易覆盖你的final方法。然而,这可能是需要的(例如,如果您的 bean 被序列化,代理需要反序列化它)。
围绕它还有更复杂的方法。可以通过代理操作您的类的字节码来注入(inject)此功能(例如删除最终修饰符,注入(inject)默认构造函数,......)甚至可能将其与继承混合使用,但这还没有实现(和支持多个 JVM 实现也很重要。
来自链接资源的注释表明这是计划在未来发布的:
Note
A future release of Weld will likely support a non-standard workaround for this limitation, using non-portable JVM APIs: Sun, IcedTea, Mac: Unsafe.allocateInstance() (The most efficient) IBM, JRockit: ReflectionFactory.newConstructorForSerialization()
But we didn't get around to implementing this yet.
关于java - 为什么 CDI bean 不支持 final方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20681981/