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

单例Bean注入原型Bean时TestService的name属性为null问题咨询

问题根因

三个错误叠加导致name属性始终为null:

  • 作用域代理的特性导致操作的不是同一个对象,且代理对象本身属性未初始化
    你给TestService配置了ScopedProxyMode.TARGET_CLASS后,Spring注入到其他Bean里的永远是CGLIB生成的代理对象,不是真实的TestService实例。这个代理的逻辑是:每调用一次代理的公开方法,就会从容器拿一个全新的TestService原型实例,把这次方法调用转发给新实例。
    你在test方法里先调testService.setName(a):这时代理会生成第一个TestService实例(name初始值是"hhh"),给它赋值a,方法执行完这个实例就被回收了,Spring不会缓存原型Bean。后面调testService.test()的时候,代理又生成第二个全新的TestService实例,这个实例从来没被赋值过。
    至于为什么拿到的是null不是默认的"hhh":CGLIB生成代理对象时会绕过类的构造函数和成员初始化逻辑,代理对象自己的name字段根本没执行private String name = "hhh"的赋值,默认值就是null,只要你操作的是代理对象本身而非转发的真实实例,拿到的name就是null。
  • @Lookup注解完全没生效
    你虽然给getTestService()加了@Lookup,但两个写法错误导致它根本没用:
    1. 业务逻辑里全程直接操作testService字段,从来没调用过getTestService()方法,@Lookup每次调用返回新实例的逻辑根本触发不了。
    2. @Lookup标注的方法不需要自己写实现,Spring运行时会动态重写这个方法返回新的原型实例,你写的return testService;逻辑本身是无效的。
  • 字段缺少注入配置(大概率是贴代码时遗漏)
    你贴的TestController代码里,testService字段没有加@Autowired/@Resource这类自动注入注解,正常情况下Spring不会给这个字段赋值,直接访问会抛空指针。就算你实际代码里加了注入注解,注入进来的也只是前面说的代理空壳,不是真实的TestService实例。
修复方式

两种原型Bean注入方案选一个就行,不要同时混用:

  1. 选@Lookup方案:删掉TestService上@Scope注解里的proxyMode = ScopedProxyMode.TARGET_CLASS配置,只保留原型作用域声明;删掉TestController里的testService成员变量,在test方法里直接调用getTestService()拿到原型实例,所有set、test操作都在这个拿到的实例上执行。
  2. 选作用域代理方案:删掉@Lookup注解和对应的getTestService方法,注意不要在原型Bean里跨方法维护状态——因为每调用一次方法就会生成新实例,上一次方法设置的属性不会保留到下一次调用。

内容的提问来源于stack exchange,提问作者derrick.yang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:48:45