【问题标题】:How to @Autowire a RequestScoped bean only in web requests如何仅在 Web 请求中 @Autowire 一个 RequestScoped bean
【发布时间】:2021-04-25 09:55:18
【问题描述】:

最近,我知道 RequestScoped bean 不能在 Web 事务之外使用。

问题是在网络事务之外我不想使用那个 bean,而不是出错。

我怎样才能做到这一点?

使用请求范围 bean 的组件:

@Component
public class JavaComponent {

    @Autowired
    private RequestScopedBean requestScopedBean;
   
    @Override
    public void doStuff() {
        // TODO if in web transaction, use RequestScopedBean , otherwhise don't

    }
}

豆子:

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {

    public String getInfo() {
        return "information about the web transaction";
    }

}

编辑:尝试在 Web 请求之外使用 JavaComponent 时遇到的错误是:

org.springframework.beans.factory.BeanCreationException: 错误 创建名为“JavaComponent.requestScopedBean”的bean:范围 'request' 对当前线程无效;考虑定义一个 如果您打算从 单身人士;嵌套异常是 java.lang.IllegalStateException: No 找到线程绑定请求:您指的是请求属性吗 在实际 Web 请求之外,或在 最初的接收线程?如果您实际上是在 一个网络请求,仍然收到此消息,您的代码可能是 在 DispatcherServlet/DispatcherPortlet 之外运行:在这种情况下, 使用 RequestContextListener 或 RequestContextFilter 来公开 当前请求。

我在 Web 请求线程之外使用 bean 的方式是让 @Async 方法在单独的线程中运行。

【问题讨论】:

  • 您遇到什么错误?另外,在 Web 请求的上下文之外使用 JavaComponent 的用例是什么?
  • 我已经用你的问题的答案编辑了这个问题。谢谢
  • 不,我不想在异步请求中使用请求范围的 bean,我只想在 Web 请求之外时不要使用它。
  • 我明白这一点。使用proxyMode(如答案之一所示)将防止错误。这意味着您现在可以正确初始化 bean。至于异步请求,您应该能够在运行时处理丢失的请求范围

标签: java spring spring-boot dependency-injection


【解决方案1】:

仅自动装配 ApplicationContext 并查找您的请求范围 bean,然后执行 null 检查。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

@Service
public class TestService {

    @Autowired
    private ApplicationContext applicationContext;

    public void myMethod() {
        RequestScopedBean bean = applicationContext.getBean(RequestScopedBean.class);
        if (bean != null) {
            // do stuff
        }
    } 
}

【讨论】:

    【解决方案2】:

    我想出了一个更好的解决方案,因为 applicationContext.getBean() 在调用时会抛出异常,相反,最好检查当前线程是否在 Web 请求上下文中执行,然后获取 bean。

    我还测试了性能,get bean 非常快(0ms)可能是因为请求范围 bean 很轻

    /**
    * The Class AuditConfig.
    */
    
    @Component
    public class AuditConfig implements AuditorAware<String> {
    
        /**
         * The Constant SYSTEM_ACCOUNT.
         */
        public static final String SYSTEM_ACCOUNT = "system";
    
        @Autowired
        private ApplicationContext context;
    
        /**
         * Gets the current auditor.
         *
         * @return the current auditor
         */
        @Override
        public Optional<String> getCurrentAuditor() {
            return Optional.ofNullable(getAlternativeUser());
        }
    
        private String getAlternativeUser() {
         try {
             // thread scoped context has this != null
             if (RequestContextHolder.getRequestAttributes() != null) {
                 Object userBean = context.getBean(AuditRequestScopedBean.BEAN_NAME);
                 if (StringUtils.isNotBlank(((AuditRequestScopedBean) userBean).getUser())) 
                 {
                     return ((AuditRequestScopedBean) userBean).getUser();
                 }
              }
            } catch (Exception e) {
                return SYSTEM_ACCOUNT;
            }
            return SYSTEM_ACCOUNT;
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2011-03-11
      • 1970-01-01
      • 2016-05-15
      • 1970-01-01
      • 2019-08-04
      • 2017-11-26
      • 2014-01-27
      • 2013-12-07
      • 2012-05-14
      相关资源
      最近更新 更多