如何使用Spring @RequestScope组件的计算值初始化Domain数据类属性
推荐最佳实践
方案1:使用Spring托管的工厂类创建Domain实例(首选)
这是Spring生态下最符合规范、无额外侵入性的方案,完全避免了非托管对象的依赖注入问题:
- 定义一个Spring托管的工厂Bean,直接注入你需要的
CurrentInstance请求域组件 - 所有
Domain1Config实例统一通过工厂方法创建,创建时自动注入当前请求的instanceId作为id
示例代码:
@Component class Domain1ConfigFactory( // Spring会自动注入当前请求对应的CurrentInstance实例 private val currentInstance: CurrentInstance ) { /** * 创建Domain1Config实例,自动填充id属性 */ fun create(client: String, size: String): Domain1Config { val instanceId = requireNotNull(currentInstance.getCurrentInstanceId()) { "当前请求未初始化instance ID,请检查CurrentInstance赋值逻辑" } return Domain1Config( id = instanceId, client = client, size = size ) } }
使用方式:在所有需要创建Domain1Config的Spring托管类(Controller、Service等)中注入Domain1ConfigFactory,调用create方法即可,不需要手动处理id赋值。
优势:
- 无任何黑科技、无额外配置依赖,完全符合Spring依赖注入规范
- 类型安全,编译期即可检查依赖是否完整
- 对原有的
Domain1Config无侵入,也不需要修改CurrentInstance的代码 - 单元测试方便,只需要Mock工厂的返回值即可
方案2:使用Spring自带请求上下文工具获取值(轻量备选)
如果你不想引入工厂类,可以使用Spring自带的RequestContextHolder获取请求属性,比自己维护ThreadLocal安全很多,Spring会在请求结束后自动清理上下文,不存在内存泄漏风险:
- 改造
CurrentInstance的setCurrentInstanceId方法,将值存入请求上下文 - 编写顶层工具方法从请求上下文取值,作为
Domain1Config的id默认值
示例代码:
// 工具函数,从Spring请求上下文获取instanceId fun getCurrentRequestInstanceId(): String? { return RequestContextHolder.getRequestAttributes()?.getAttribute( "currentInstanceId", RequestAttributes.SCOPE_REQUEST ) as? String } // 改造CurrentInstance的set方法 fun setCurrentInstanceId(instanceToSet: String) { currentInstance = instanceToSet // 存入请求上下文 RequestContextHolder.getRequestAttributes()?.setAttribute( "currentInstanceId", instanceToSet, RequestAttributes.SCOPE_REQUEST ) } // Domain类id默认值使用工具函数 @Document data class Domain1Config( @Id val id: String = requireNotNull(getCurrentRequestInstanceId()) { "请求上下文无instanceId" }, val client: String, val size: String ) : Serializable
注意:该方案要求Domain1Config必须在请求线程内创建,单元测试时需要手动模拟请求上下文。
不推荐使用AspectJ织入方案的原因
@Configurable + AspectJ织入本身属于Spring的边缘特性,仅适合大量域对象需要依赖注入的场景,在Kotlin + 高版本JDK环境下兼容性问题多,配置维护成本极高,远不如上述两个方案简单可靠,一般情况下不需要使用。
内容的提问来源于stack exchange,提问作者redAce
相关产品推荐
相关产品推荐

