You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

java.lang.reflect.Field.set修改ApplicationScoped Bean字段失败求助

问题

我遇到了一个奇怪的行为差异:通过反射修改字段值时,Singleton EJB的字段值能正常更新,但ApplicationScoped CDI Bean的字段值却没有变化。不过改用AnnotatedParameter配合Method.invoke调用setter方法的方式修改值是有效的。我查了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));
    }
}
原因分析
  • CDI代理机制的差异:ApplicationScoped CDI Bean默认会被CDI容器创建代理类(比如基于接口的动态代理或子类代理),你通过CDI.current().select(bc).get()获取到的是代理对象而非真实Bean实例。直接反射修改代理对象的字段,实际改的是代理类自身的字段,而非真实Bean实例的字段,后续使用Bean时自然看不到值的变化。
  • Singleton EJB的实例特性:Singleton EJB由EJB容器直接管理,不会生成CDI风格的代理(或代理逻辑完全不同),你获取到的引用就是真实的Singleton实例本身,所以反射修改字段值会直接作用在真实实例上,能看到预期的变化。
  • setter方法有效的原因:不管是CDI代理还是EJB代理,调用方法时都会将请求转发到真实的Bean实例上。通过Method.invoke调用setter方法,实际是在真实实例上执行赋值操作,自然能修改到正确的字段值。

内容的提问来源于stack exchange,提问作者Eduard Drenth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 06:13:16