为什么CDI bean不支持最终方法

den*_*ini 7 java java-ee cdi

我刚刚在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].
Run Code Online (Sandbox Code Playgroud)

因为他不喜欢CDI bean中的final方法,所以错误很明显,但是我无法理解为什么.

在这个链接

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

他们解释说它与序列化有关但我不明白为什么用最终方法序列化类应该比使用非最终方法更难.

Mat*_*ias 13

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

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

然后,这个代理处理所有的魔法,以确保你总是有一个适合你的上下文的bean(这个bean的所有成员变量bean都指向恰到好处的bean).

所以你并没有真正收到你想要注入的bean的类型,而是接受那个bean的代理子类.这对最终方法和类以及私有构造函数不起作用.

如果类不是final,则代理可以扩展此类,但是它不能轻易覆盖您的最终方法.然而,这可能是需要的(例如,如果您的bean被序列化,则代理需要对其进行反序列化).

围绕这一点,有更复杂的方法.可以通过代理操作类的字节代码来注入此功能(例如删除最终修饰符,注入默认构造函数,......)甚至可以将它与继承混合使用,但这只是没有实现,但是(和同样非常容易支持多个JVM实现).

从链接的资源中,注释表明这是为将来的版本计划的:

注意

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

但是我们还没有实现这个目标.


Fir*_*rks 10

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

  • 问题相同,代理类重写方法,但如果它们最终代理不能覆盖它们 (2认同)