如何仅在 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;
}
}
最近,我了解到 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;
}
}