Spring和交叉上下文:WebAsyncManager无法转换为WebAsyncManager

我想在Spring应用程序中使用交叉上下文function,因此我可以将一些webapp1 JSP导入到webapp2 JSP中。 我正在使用包含Tomcat 7.0.42(vFabric TC Server)和Spring Framework 3.2.8的Eclipse STS。

我已将Tomcat conf / context.xml配置为:`

...`. 

在webapp2 JSP中我使用`

 `. 

当我调用webapp2 JSP时出现此错误:

 HTTP Status 500 - javax.servlet.ServletException: javax.servlet.jsp.JspException: `java.lang.ClassCastException:` `org.springframework.web.context.request.async.WebAsyncManager cannot be cast to` org.springframework.web.context.request.async.WebAsyncManager` 

有人遇到过这种情况么?

看起来Spring还没有为交叉上下文请求处理做好准备(至少没有一点点黑客攻击)。

FrameworkServlet 总是尝试从请求属性中获取WebAsyncManager 。 它的提取方式无法在不同的上下文 (类加载器)中工作。

我看到两种可能性如何解决这个问题:

  • 实现自己的include JSP标记,它将包装原始请求,以便Spring特定的属性(通常是以org.springframework开头的那些)到第二个上下文。
  • 将Spring JAR放在共享的类加载器路径中(这可能是更简单的方法)。

Atlassian似乎有一个使用此filter的解决方法:

https://docs.atlassian.com/atlassian-confluence/latest/com/atlassian/confluence/internal/web/filter/spring/IgnoreWebAsyncManagerFilter.html

根据文件:

此filter用于解决使用SpringMVC的插件的问题。 Spring的OncePerRequestFilter调用WebAsyncUtils.getAsyncManager(ServletRequest)来获取WebAsyncManager以确定请求是否是异步的。 getAsyncManager将它创建的WebAsyncManager缓存为ServletRequest上的一个属性。

由于宿主应用程序和插件框架使用来自不同ClassLoader的Spring类,因此缓存的WebAsyncManager会导致使用SpringMVC的插件的ClassCastExceptions。

为了避免这些exception,此filter会检测Spring何时尝试缓存其WebAsyncManager并忽略该调用,从而确保它永远不会添加到请求中。 每次调用getAsyncManager(ServletRequest只会创建一个新的,然后立即丢弃。但这意味着在宿主应用程序中处理的请求部分从其ClassLoader创建实例,并在插件中处理该部分framework从OSGi ClassLoader创建实例。

也许您可以尝试获取源代码,如果您这样做,请回复并发送给我课程,或者您可以重现该行为。 似乎在每个请求上创建一个新对象,因此它避免了为交叉上下文序列化它。

我今天遇到了这个问题,根据@Sylvain Lecoy的回答,我想出了一个servletfilter的实现,它以Atlassianfilterjavadoc描述的方式运行。 将它放在任何调用WebAsyncUtils.getAsyncManager(ServletRequest)filter之前,似乎可以修复任何类加载器/跨上下文问题。

 public class IgnoreWebAsyncManagerFilter implements Filter { static class IgnoreWebAsyncManagerCacheServletRequest extends HttpServletRequestWrapper { /** * Creates a ServletRequest adaptor wrapping the given request object. * * @param request the {@link ServletRequest} to wrap. * @throws IllegalArgumentException if the request is null */ IgnoreWebAsyncManagerCacheServletRequest(HttpServletRequest request) { super(request); } /** * {@inheritDoc} */ @Override public void setAttribute(String name, Object o) { if (!name.equals(WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE)) { super.setAttribute(name, o); } } } /** * {@inheritDoc} */ @Override public void init(FilterConfig filterConfig) throws ServletException { } /** * {@inheritDoc} */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(new IgnoreWebAsyncManagerCacheServletRequest((HttpServletRequest) request), response); } /** * {@inheritDoc} */ @Override public void destroy() { } 

注意:这假设所有请求都是HttpServletRequest实例,但可以修改为更安全。

我们在混合应用程序(开发:Spring Boot应用程序/生产:Liferay portlet;我们的Liferay服务器上发生的exception)中使用此exception进行了数天的斗争。

在我们的例子中,禁用所有(不需要的)servletfilter有助于: