我在weblogic中运行了2个示例(我使用了具有依赖范围的bean):
1)该bean没有任何拦截器或装饰器:该bean没有被代理
2)该bean具有拦截器:该bean已被代理
我认为CDI中有两种类型的代理:
1)客户端代理:此代理会覆盖Bean类的所有非私有方法,当调用这些覆盖的方法时,代理会查找Bean的正确实例(或第二种代理),然后转发调用到实际的bean实例上(基于this链接)。对于依赖范围,不会创建此代理
2)还有另一个用于应用拦截器和装饰器的代理,它是在bean具有装饰器或拦截器时创建的。
我对第二种代理的假设正确吗?规范对此有何规定?
答案 0 :(得分:2)
您确实做了一个很好的调查,并且在大多数情况下您是对的。 这是详细信息。
代理
确实可以代理普通作用域的bean(@ApplicationScoped
,RequestScoped
,...),您无法掌握实际实例,而得到的只是一个client proxy。
使用不是普通作用域的@Dependent
,您基本上希望每次都注入新实例,因此无需代理它。
以上内容在CDI规范中有所提及,尽管不够精确,不能为他们提供可操作的实现空间-用户不必真正关心是否有代理,也可以调用方法正常工作。
拦截器和装饰器
继续使用拦截器-我所了解的规范对此一无所知,并让实现者自由选择要怎么做。以下细节是 Weld-specific (特定于焊接的),尽管据我回忆,OWB也有类似之处。无论如何,实际上没有太多选择。
对于每个拦截器/装饰器,都会创建一个“代理”,实际上是一个子类,该子类允许进行拦截/装饰。该子类将替换原始Bean,并且所有调用都将通过该子类(例如,它在基础Bean存储区中而不是原始实例中)。
同样,从用户的角度来看,这没有什么区别,您不必担心。
用于代理/子服务器的额外工具
有时候,非常少,而且很可能只有在开发CDI库时,您才真正需要查看注入的bean是客户端代理还是子类。
Weld为此提供了工具,每个具有客户端代理的bean都从Weld API实现WeldClientProxy
接口。该界面允许您获取实际实例和一些元数据。
同样,每个被拦截和修饰的bean都将WeldContruct
实现为标记接口。