Spring中proxyMode与scopeName底层原理及请求域Bean注入疑问
Spring request scope代理对象哈希值不变问题解答
核心原因
你在控制器中打印的numberGenerator不是真实的业务实例,是Spring生成的全局单例CGLIB代理对象,它的内存地址固定,因此System.identityHashCode的返回值永远不变。
详细机制说明
- 你的
RandomNumberGenerator配置了proxyMode = ScopedProxyMode.TARGET_CLASS,Spring会基于CGLIB生成该类的子类作为代理类。控制器是默认单例scope,初始化时只会注入一次固定的代理对象,这个代理对象在容器启动阶段就创建完成,生命周期和容器一致,不会随请求更换,因此它的identityHashCode永远相同。 - 每次请求触发
getNumber()方法调用时,代理对象不会直接执行业务逻辑,会先从当前请求的上下文里查找对应request scope的真实RandomNumberGenerator实例:如果找不到就调用构造方法创建新实例,存入request域后再转发方法调用。这就是你每次请求都会看到构造方法被调用的原因。 - 你当前的打印逻辑输出的是外层代理对象的哈希值,而非每次新建的真实业务实例的哈希值,所以会出现构造触发但哈希不变的现象。
验证方法
你可以在RandomNumberGenerator内部打印当前真实实例的哈希值,就能看到每次请求都生成了新的实例:
public RandomNumberGenerator() { System.out.println("Constructor is called! 真实实例哈希:" + System.identityHashCode(this)); number = Math.random(); }
修改后运行控制台会输出两个哈希值:一个是固定不变的代理对象哈希(控制器打印),另一个是每次请求都变化的真实实例哈希(构造方法打印)。
内容的提问来源于stack exchange,提问作者Hatef Alipoor
相关产品推荐
相关产品推荐

