代码之家  ›  专栏  ›  技术社区  ›  Eduard Drenth

java.lang.reflect.field.set(obj,value)在应用程序范围内失败

  •  0
  • Eduard Drenth  · 技术社区  · 7 月前

    以下代码成功运行,但当引用是应用程序范围的bean时,值不会更改。当bean是Singleton EJB时,值确实会发生变化。

    通过AnnotatedParameter和Method.invoke更改值确实会更改值。

    有人知道是什么导致了行为上的差异吗?我在(java)文档、规范或其他地方找不到原因。

    InjectionPoint ip = ....;                
    Class bc = ip.getMember().getDeclaringClass();
    Object reference = CDI.current().select(bc).get();
    Annotated a = ip.getAnnotated();
    Object value = ....;
    if (annotated instanceof AnnotatedField af) {
        Field f = af.getJavaMember();
        try {
            boolean ac = f.canAccess(reference);
            f.setAccessible(true);
            f.set(reference, value);
            f.setAccessible(ac);
        } catch (IllegalAccessException e) {
            log.error(String.format("error updating %s with %s",
                            f, value));
        }
    }
    
    1 回复  |  直到 7 月前
        1
  •  1
  •   Rob Spoor    7 月前

    使用CDI,注入的实际实例是代理。它是bean类生成的子类的实例。这就是为什么CDI有一些局限性,比如需要一个无参数构造函数和无最终方法。生成的子类具有一个无参数构造函数,该构造函数调用bean类的无参数构造函数( super() ),并且每个方法都被覆盖。在代理内部(以某种方式)有一个对单个实例的引用;被覆盖的方法各自调用此实例的相同方法。

    这个 reference 您已经拥有bean类的所有字段,但如果在调试器中检查它们,您可能会看到它们都是 null 这是我迄今为止的经验。唯一重要的字段是对单个实例的内部引用。您设置的字段将被代理忽略。

    @Singleton 另一方面,在JBoss和Quarkus中,都没有代理。注入的实例就是单例实例本身。

    一些链接记录了这一点: