【问题标题】:Get the real object from CDI Proxy从 CDI 代理获取真实对象
【发布时间】:2019-01-29 14:07:54
【问题描述】:

我寻找了一个干净的 CDI 解决方案,而不是依赖于 WELD 的解决方案,但到目前为止什么都没有......

我需要测试我使用@Inject @Any MyInterface beans 获得的对象列表中的每个元素是否是代理,而当 true 我需要获取真实对象进行自省并获取对象的所有属性。

我的 WELD 实现:

MyInterface interf = obj;
if (isProxy(interf )) {
        interf = (Config) ((TargetInstanceProxy)interf ).getTargetInstance();
}

isProxy 是这样定义的(CDI 解决方案?):

public boolean isProxy(Object obj) {
    try{
        return Class.forName("org.jboss.weld.bean.proxy.ProxyObject").isInstance(obj);
    } catch (Exception e) {
        LOGGER.error("Unable to check if object is proxy", e);
    }
    return false;
}

任何建议/适应症。在官方文档中,我发现没有提到自省 (here)

然后我想通过以下方式获取 bean 的所有属性:

Arrays.stream(interf.getClass().getDeclaredFields()).forEach(
                        field -> extractStuff(...)
                );

我们使用 Wildfly 和 WELD,但不想将我们绑定到 CDI 的实现。 提前致谢!

编辑: 更准确地说,问题是:您知道 WELD已经 使用 TargetInstanceProxy 实施的干净 CDI 解决方案吗?如果我需要回学校,或者如果我明白我在写什么。感谢您抽出时间提供帮助!

【问题讨论】:

  • 我想到了一个想法:为什么不能重构遗留代码并将其重写为正确的方式?为什么需要这样的测试?通常情况下,不需要这样做。
  • 因为他们不想 :( 对你们来说,用公司的代码做任何你想做的事情总是那么容易吗?
  • 我到底对什么投了反对票?如果人们不满意,他们会在这里投反对票吗?

标签: java cdi jboss-weld


【解决方案1】:

CDI 有意隐藏(或者说不暴露)内部,因为它们在针对接口编程时对最终用户来说应该是不重要的。此外,弄乱这个可能会导致奇怪的错误,因为您应该始终调用方法通过代理,而不是实际实例。

所以简短的回答是 - 不,没有纯粹的 CDI 方法可以做到这一点。 (至少不是预期的。)

但是,鉴于您已经在使用 Weld,还有其他方法。 Weld 附带了几乎所有的 EE 服务器,除了 TomEE,所以依赖 Weld API 应该是相当安全的。 现在我为什么要这么说 - 在 Weld 3.x (WildFly 12+) 中,API 被扩展为包含 WeldConstructWeldClientProxy,它们是由 Weld 子类(拦截器/装饰器)和/或客户端代理实现的接口 -有关更多信息,请参阅这些类的 javadocs。

所以如果你必须这样做,那么你可以像这样添加对 Weld API 的依赖:

<dependency>
  <groupId>org.jboss.weld</groupId>
  <artifactId>weld-api</artifactId>
  <version>x.y.z</version>
</dependency>

然后,在您的代码中,您可以通过以下方式检查注入的对象是否为代理:

@Inject
Foo foo;

public void doSomething() {
  if (foo instanceof WeldClientProxy) {
    // foo is a proxy
  } else {
    // not a proxy
  }
}

如果要获取实际实例,WeldClientProxy allows you to obtain Metadata 可以从中获取retrieve the underlying contextual instance。这是我可以让你最接近你所追求的东西。

【讨论】:

  • 谢谢,是的,我明白你的意思了......他们不想直接使用焊接,但感谢 +1 给了我充分的理由。 PS您说获取包装在代理中的内部类并不重要。但也许不是……为什么 Weld 开发人员要花时间提供这种可能性? CDI 缺乏反射工具正在解除武装,比如 Introspector.getBeanInfo...
  • 好吧,我们已经看到大多数集成商(即 WildFly、Payara 等)或其他一些集成 witu us (RestEasy) 的 EE 技术实际需要获取上下文实例的案例 - 因此这API 的出现是为了避免他们侵入真正的内部 Weld 类。对于最终用户,我们很少看到避免这样做不会“更干净”的情况。话虽如此,总有一些情况是肯定的:)
  • 哦,我刚刚记得,很久以前就有 CDI 要求你想要的东西,但从未实现,请参阅 issues.jboss.org/browse/CDI-10
  • 嘿@Siliarus 它重新打开了,也许他们会在 2.1 中实现它 :) 另一个需要实现一段时间的理由(焊接)!
【解决方案2】:

一个常见的选择是:

  1. 获取要解包的实例的 Bean
  2. 获取其范围 (bean.getScope())
  3. 从 bean 管理器(可注入)获取与作用域关联的上下文
  4. 如果在 CDI 上下文中可用,请执行 context.get(bean) 以获取展开的实例(在某些情况下您根本无法获取它)。

【讨论】:

    猜你喜欢
    • 2012-01-10
    • 2020-04-04
    • 2017-05-02
    • 2019-09-25
    • 1970-01-01
    • 1970-01-01
    • 2014-11-04
    • 2018-07-10
    • 2011-07-22
    相关资源
    最近更新 更多