0

Our Spring Boot web application works fine running on GlassFish 3.1.2, Spring Boot 1.2.8.

Since upgrading to Spring Boot 1.3.1 it no longer works, specifically when injecting HttpServletRequest into something like a Web Filter (e.g. a sub-class of OncePerRequestFilter) you get a "No thread-bound request found" when calling many of the methods on the request (e.g. getAttributes).

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.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.support.WebApplicationContextUtils.currentRequestAttributes(WebApplicationContextUtils.java:309)
at org.springframework.web.context.support.WebApplicationContextUtils.access$400(WebApplicationContextUtils.java:64)
at org.springframework.web.context.support.WebApplicationContextUtils$RequestObjectFactory.getObject(WebApplicationContextUtils.java:325)
at org.springframework.web.context.support.WebApplicationContextUtils$RequestObjectFactory.getObject(WebApplicationContextUtils.java:320)
at org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler.invoke(AutowireUtils.java:307)
PaulNUK
  • 4,774
  • 2
  • 30
  • 58
  • 1
    why are you injecting the request instead of using the one provided in the "doFilter" argument? – Guy Bouallet Dec 23 '15 at 15:16
  • The filter itself isn't injecting the request, it's injecting a service and the service is injecting the request. The service is used elsewhere, not just from a filter. But for the sake of this error, it can be viewed as being injected into the filter. This used to work prior to 1.3.1. I'm just putting together an example app that demonstrates the issue. – PaulNUK Dec 23 '15 at 15:22
  • 1
    What order does your custom filter have? I would guess that the problem is that it's running before RequestContextFilter – Andy Wilkinson Dec 23 '15 at 22:20
  • I've tried setting the order to 0 and 999. I don't explicitly define RequestContextFilter anywhere; perhaps Spring Boot is doing that for me ? – PaulNUK Dec 24 '15 at 09:49
  • 1
    The request context filter is added with order = -105 in Boot 1.3.0, but it isn't used at all in Boot 1.2 (only an MVC interceptor, so you can only use it in MVC components, and I'm surprised it worked at all in a filter). So there is definitely a difference, but I can't say what Glassfish is doing to screw it up. – Dave Syer Dec 25 '15 at 12:52
  • Thanks Dave - that was the clue we needed. We were injecting an http request in a service used by the filter that was running before the request context filter, and therefore a thread bound request wasn't available. We have got past this by changing our filter order to be -106. Two questions. One is this sensible and two, is the -105 defined anywhere as a public constant, so we can refer to it in a safe way ? – PaulNUK Jan 04 '16 at 10:43
  • It seems that when running glassfish we have to put our filters BELOW the request context filter, but when running in embedded we have to put our filters ABOVE the request context filter. I have no idea what is happening here. – PaulNUK Jan 11 '16 at 09:15
  • Possibly related to https://github.com/spring-projects/spring-boot/issues/4331 – PaulNUK Jan 11 '16 at 15:14

2 Answers2

1

Filters are singletons while HttpServletRequests are request scoped. When you get the error, you should be getting attributes from one request while processing another. Some checks should have been reinforced in 1.3.1 to avoid this.

Generally, it is a bad ideas to mix bean lifecycles. People run into issues because of that (i.e here, and here).

You may check method injection to handle the collaboration of bean of different lifecycles.

Community
  • 1
  • 1
Guy Bouallet
  • 2,099
  • 11
  • 16
  • I appreciate Filters are singletons but the doFilter method is called on a per request basic. Within the doFilter method we are calling code way down the stack that needs access to the request. In the code down the stack, which is used not only in filters, but elsewhere, we inject the httpServletRequest, and that has always worked up until now. It's a standard pattern, injecting something that is actually request scoped into a singleton, and works as long as the request is available. It seems that prior to 1.3.1 that request was available when doFilter was called but is no longer ? – PaulNUK Dec 23 '15 at 15:42
  • PS it's worth reinforcing the point that injecting the request still works in 1.3.1 if you use embedded Tomcat, but not if you deploy to Glassfish, – PaulNUK Dec 23 '15 at 15:48
  • I don't know how you managed to make the application work but I'm quite confident that you are running into issue whenever you have heavy concurrent requests with different attributes. Please check my updates for further details. – Guy Bouallet Dec 24 '15 at 09:40
  • I now have a simple test application that demonstrates the issue perfectly. There are no concurrent requests - I can start the application and hit it with a single request and get the error every time. I revert to 1.2.8 and it works, I switch back to 1.3.1 and it doesn't. Not sure if you have a glassfish 1.3 install anywhere (that is a pain to set up) but I can easily provide a test project to demonstrate the problem. – PaulNUK Dec 24 '15 at 09:47
  • OK, so assuming it's a bad idea to mix in request scoped stuff in a filter, I can pass down stuff from the request being dealt with in the filter instead of injecting the request at a lower level. This seems a bit clumsy but if that's the way to do it, c'est la vie. But I'm still interested as to why it worked before, and what changed in 1.3 to break it for Glassfish only. – PaulNUK Dec 24 '15 at 09:57
0

It turns out that Glassfish 3.3 processes filters in the reverse order to the order you specify when adding FilterRegistrationBeans

So if you're using an embedded context, add your filters before (higher number) the RequestContextFilter order of -105, and if you're running Glassfish, add them after (lower number) the RequestContextFilter.

Not sure if this is a peculiarity of Glassfish 3.3 but that's the issue.

PaulNUK
  • 4,774
  • 2
  • 30
  • 58