Spring自定义定时刷新Scope的get方法仅启动调用一次问题咨询
问题根因
你的自定义Scope本身实现逻辑没有问题,get方法只调用一次是Spring单例Bean的注入特性导致的:
你将自定义Scope的Bean直接注入到了单例的Controller中:Spring在启动初始化Controller时,会调用一次你的Scope的
get方法拿到Bean实例,直接赋值给Controller的dateString字段,后续Controller使用的永远是首次注入的这个实例,自然不会再触发Scope的get逻辑。
解决方案
有两种常用的适配方案:
方案1:给自定义Scope添加动态代理
在声明Bean的@Scope注解中指定代理模式,让Spring注入代理对象,每次调用Bean方法时自动去Scope中拉取最新实例:
@Bean @Scope(scopeName = "CyberArk", proxyMode = ScopedProxyMode.TARGET_CLASS) public String dateString(){ return LocalDateTime.now().toString(); }
- 如果你的Bean是接口实现类,可使用
ScopedProxyMode.INTERFACES代理模式,性能更优。
方案2:注入ObjectProvider延迟获取
不在初始化阶段就注入固定实例,而是注入对象提供者,每次需要使用时主动拉取最新实例:
@RestController public class HelloWorld { @Autowired private ObjectProvider<String> dateStringProvider; @RequestMapping("/") public String index() { // 每次调用都会触发自定义Scope的get方法 return dateStringProvider.getIfAvailable(); } }
现有实现优化建议
你当前的Scope实现在实例过期时直接覆盖了Map中的旧实例,没有触发对应的销毁回调,建议修改get方法的过期逻辑,先处理旧实例的销毁:
@Override public Object get(String name, ObjectFactory<?> objectFactory) { if (!scopedObjects.containsKey(name) || scopedObjects.get(name).getKey() .isBefore(LocalDateTime.now().minusMinutes(scopeRefresh))) { // 先触发旧实例的销毁回调 if (destructionCallbacks.containsKey(name)) { destructionCallbacks.get(name).run(); destructionCallbacks.remove(name); } scopedObjects.put(name, Pair.of(LocalDateTime.now(), objectFactory.getObject())); } return scopedObjects.get(name).getValue(); }
内容的提问来源于stack exchange,提问作者Evan
相关产品推荐
相关产品推荐

