如何仅在 Web 请求中 @Autowire RequestScoped bean

How to @Autowire a RequestScoped bean only in web requests

最近,我了解到 RequestScoped bean 在 web 事务之外不可用。

问题是在 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: Error creating bean with name 'JavaComponent.requestScopedBean': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

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

仅自动装配 ApplicationContext 并查找您的请求作用域 bean,然后执行空检查。

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
        }
    } 
}

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

我还测试了性能,get bean 非常快(0 毫秒)可能是因为请求作用域 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;
    }

}