标准的Spring Web应用程序(由Roo或"Spring MVC Project"模板创建)使用ContextLoaderListener和创建一个web.xml DispatcherServlet.为什么他们不仅使用DispatcherServlet并使其加载完整的配置?
我知道ContextLoaderListener应该用于加载非Web相关的东西,而DispatcherServlet用于加载与Web相关的东西(Controllers,...).这导致两个上下文:父上下文.
背景:
几年来我一直以这种标准方式做这件事.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Handles Spring requests -->
<servlet>
<servlet-name>roo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Run Code Online (Sandbox Code Playgroud)
这通常会导致两个上下文及其之间的依赖关系出现问题.在过去,我始终能够找到解决方案,我强烈认为这使得软件结构/架构总是更好.但现在我面临着两种情境事件的问题.
- 然而这让我重新思考这两个上下文模式,我问自己:为什么我要把自己带入这个麻烦,为什么不用一个加载所有弹簧配置文件DispatcherServlet并ContextLoaderListener完全删除.(我仍然会有不同的配置文件,但只有一个上下文.)
有没有理由不删除ContextLoaderListener?
我有一个Web应用程序,它在一个独立的线程中运行Spring Integration逻辑.问题是,在某些时候,我的Spring Integration逻辑尝试使用请求范围的bean,然后我得到以下错误:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.tenantContext': 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 …Run Code Online (Sandbox Code Playgroud) 场景:我们有一个在Websphere中运行的Spring托管Web应用程序.(Spring 3.0.x,WAS 7)webapp通过Spring WorkManagerTaskExecutor(配置线程池大小为10)利用Websphere的工作管理器来执行计算密集型数据库读取操作.所以基本上,一个请求来生成,比方说,生成10个不同的文档.要生成文档,只需要db读取来收集/处理数据.因此,我们基本上产生10个线程来处理10个文档,最后收集10个工作者返回的10个文档并合并它们并向客户端写回一个大响应.我们确定的是,当10个线程正在收集/处理数据时,会产生大量类似的数据库调用.所以我们想出的是围绕最常执行的db方法创建一个Aspect来缓存响应.方面配置为单例,方面使用的缓存自动连接到方面,并将范围设置为请求范围,以便每个请求都有自己的缓存.
问题:现在这个方法的问题是,当线程正在进行数据库调用而Aspect是interjects时,我们会遇到java.lang.IllegalStateException: No thread-bound request found异常.我理解的是完全有效的,因为线程正在请求上下文之外执行.
有没有办法绕过这个问题?是否可以将带有请求范围缓存的方面应用于这些线程调用的方法?
我需要在我的Spring Boot应用程序中添加一个监听器,在web.xml中看起来像
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
Run Code Online (Sandbox Code Playgroud)
我使用no-web.xml配置,所以我有一个类似的
public class AppFilterConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF8");
filter.setForceEncoding(true);
Filter[] filters = new Filter[1];
filters[0] = filter;
return filters;
}
private int maxUploadSizeInMb = 5 * 1024 * 1024; // 5 MB
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected void registerDispatcherServlet(ServletContext servletContext) { …Run Code Online (Sandbox Code Playgroud) 我有问题,我想将我的Spring WebMVC应用程序的一些进程外包到单独的Threads中.这很容易并且有效,直到我想使用一个使用全局请求的类userRightService.这在线程中不可用,我们遇到了一个问题,这几乎是可以理解的.
这是我的错误:
java.lang.RuntimeException:
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'scopedTarget.userRightsService': 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: Cannot ask for request attribute -
request is not active anymore!
Run Code Online (Sandbox Code Playgroud)
好的,够清楚了.我试图通过实现此解决方案来保持请求上下文:
这是我的runnable类:
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class myThread implements Runnable {
private RequestAttributes context;
public DataExportThread(RequestAttributes context) {
this.context = context;
}
public …Run Code Online (Sandbox Code Playgroud) 我正在使用 SpringBoot 1.5.2 版本。我有一个异步 REST 调用,它会生成单独的 java 线程来完成长时间运行的作业。长时间运行的作业需要更新数据库表,我在其中配置了 Spring 审核 bean 以使用当前登录用户名更新表。我遇到的问题是:通过调用 setThreadContextInheritable(true) 启用可继承标志后,传递给执行长时间运行的数据库更新的子线程的 ServletRequestAttributes 对象在子线程完成其工作之前被标记为“非活动”,最终导致当审核 bean 尝试从 RequestContextHolder 中缓存的 ServletRequestAttributes 访问用户名时出错。
要打开可继承标志,请参阅Scope 'session' is not active for the current thread; IllegalStateException:未找到线程绑定请求
这是获取我到目前为止所拥有的内容的主要代码:
@Override
public Executor getAsyncExecutor() {
SimpleAsyncTaskExecutor executor = new
SimpleAsyncTaskExecutor(appProperties.threadNamePrefix);
return executor;
}
@Bean
public ServletRegistrationBean registerAirportDispatchServlet() {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
AnnotationConfigWebApplicationContext applicationContext =
new AnnotationConfigWebApplicationContext();
dispatcherServlet.setApplicationContext(applicationContext);
dispatcherServlet.setThreadContextInheritable(true);
ServletRegistrationBean servletRegistrationBean =
new ServletRegistrationBean(dispatcherServlet, "/*");
servletRegistrationBean.setName("AirportSCSDispacherServlet");
return servletRegistrationBean;
}
@Bean
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, …Run Code Online (Sandbox Code Playgroud) 我的应用程序有多个弹簧安全配置,其中一个恰好是Oauth2(使用此 eaxmple).
一般来说Spring安全性通过以下方式插入:
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.addFilter(GzipFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
context.addFilter(new FilterHolder( new DelegatingFilterProxy( DEFAULT_FILTER_NAME ) ), "/*",EnumSet.allOf( DispatcherType.class ));
AnnotationConfigWebApplicationContext securityContext = new AnnotationConfigWebApplicationContext();
securityContext.setConfigLocation("com.test.auth");
DispatcherServlet dispatcherServlet = new DispatcherServlet(securityContext);
context.addServlet(new ServletHolder(dispatcherServlet), "/");
context.addServlet(new ServletHolder(new ServletContainer(createResourceConfig(AuthController.class))), "/auth/*");
Run Code Online (Sandbox Code Playgroud)
Oauth2看起来像这样:
@Order(4)
@EnableOAuth2Client
@EnableWebSecurity
@Configuration
public class Oauth2Config extends WebSecurityConfigurerAdapter {
@Bean
@Order(0)
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
@Autowired
private OAuth2ClientContext oauth2ClientContext;
@Autowired
private OAuth2ClientContextFilter oauth2ClientContextFilter;
@Autowired
private AuthConfig authConfig;
private OAuth2ProtectedResourceDetails authorizationCodeResource() {
AuthorizationCodeResourceDetails …Run Code Online (Sandbox Code Playgroud)