Spring Boot注入request作用域Bean报ScopeNotActiveException如何解决
问题根因
报错的核心原因是 request作用域Bean的调用时机不合法:
com.common.Security被声明为request作用域,只有HTTP请求处于活跃状态时Spring才会生成对应的实例,每个请求对应独立实例- 你虽然已经为
Security配置了ScopedProxyMode.TARGET_CLASS作用域代理,解决了单例Bean注入短作用域Bean的类型兼容问题,但WebServiceConfig是默认单例的配置类,内部创建webServiceTemplate的@Bean方法会在Spring容器启动阶段就执行,此时没有活跃的HTTP请求,代理无法获取到真实的Security实例,因此触发Scope 'request' is not active异常。
解决方案
方案1:调整Security的调用时机(推荐)
不要在webServiceTemplate的初始化阶段访问Security的属性,改为请求处理阶段动态获取:
- 新增Spring上下文工具类,用于手动获取Bean:
@Component public class ApplicationContextProvider implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } public static <T> T getBean(Class<T> clazz) { return context.getBean(clazz); } }
- 给
WebServiceTemplate添加拦截器,在请求执行时再获取Security实例填充参数:
@Configuration public class WebServiceConfig { // 移除Security的直接注入 @Bean public WebServiceTemplate webServiceTemplate() { WebServiceTemplate template = new WebServiceTemplate(); template.setInterceptors(new ClientInterceptor[]{securityParamInterceptor()}); // 其他基础配置 return template; } @Bean public ClientInterceptor securityParamInterceptor() { return new ClientInterceptor() { @Override public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException { // 此时处于请求处理阶段,request作用域活跃,可以正常获取Security实例 Security security = ApplicationContextProvider.getBean(Security.class); // 从security中取出参数,写入webservice请求头/报文即可 return true; } // 剩余接口方法默认实现省略 }; } }
方案2:使用ObjectProvider延迟注入
如果要保留在WebServiceConfig中注入Security的逻辑,可以用ObjectProvider包装避免初始化阶段触发实例化:
@Configuration public class WebServiceConfig { @Autowired private ObjectProvider<Security> securityProvider; @Bean public WebServiceTemplate webServiceTemplate() { WebServiceTemplate template = new WebServiceTemplate(); // 注意:此处不能调用securityProvider.getObject(),必须等到请求处理阶段再调用获取实例 return template; } }
方案3:调整Security的作用域(仅业务允许时使用)
如果Security中存储的不是请求级别的独有信息,可以将它的作用域调整为单例/会话作用域,从根源避免作用域不匹配问题:
// 示例改为单例,去掉request作用域配置 @Service @EnableConfigurationProperties(SecurityProperties.class) public class Security { // 原有逻辑 }
内容的提问来源于stack exchange,提问作者Daniel Pomrehn
相关产品推荐
相关产品推荐

