Brian
Brian

Reputation: 6450

IllegalStateException when using Spring RequestContextHolder

I am using a RequestContextHolder in a filter to record a piece of data, and want to access it in a POJO (wired up via Spring) later. I'm getting an exception which suggests I'm doing something wrong here, would appreciate any guidance on what that is.

Filter code (in a doFilter() method, whose logging confirms it's being called):

RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
if (attrs == null)
{
    logger.info("Creating new ServletRequestAttributes");
    attrs = new ServletRequestAttributes(servletRequest);
}

attrs.setAttribute("my_attr", "hello there!", RequestAttributes.SCOPE_REQUEST);

RequestContextHolder.setRequestAttributes(attrs);

POJO code:

RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
if (attrs != null && attrs.getAttribute("my_attr", RequestAttributes.SCOPE_REQUEST) != null)
{
    String myAttr = (String) attrs.getAttribute("my_attr", RequestAttributes.SCOPE_REQUEST);
    logger.debug("Got it: ", myAttr);
}

I am seeing this exception coming from Tomcat though:

java.lang.IllegalStateException: The request object has been recycled and is no longer associated with this facade
    at org.apache.catalina.connector.RequestFacade.getAttribute(RequestFacade.java:259)
    at org.springframework.web.context.request.ServletRequestAttributes.getAttribute(ServletRequestAttributes.java:98)
    at com.mycompany.MyClass(MyClass.java:50)

I do wonder if having the "set data" in a filter, and "get data" via the real work of the request could be in play here, but not sure how best to accommodate that, if it even is relevant?

Upvotes: 2

Views: 8894

Answers (1)

kschneid
kschneid

Reputation: 5694

The error is likely caused by the fact that you're making Spring maintain a thread-local handle to a request object that is no longer valid. The details probably don't matter all that much since a different approach is in order.

One of the following will take care of automatically setting and clearing thread-local state properly: DispatcherServlet, RequestContextListener or RequestContextFilter. You need to figure out which one makes the most sense for how Spring is used with your app. Your filter and POJO code shouldn't need to make use of classes like RequestContextHolder directly. What should happen is that you declare a proxied, request-scoped bean for the attribute you want to access:

<bean id="myAttr" scope="request">
  <aop:scoped-proxy/>
</bean>

Then, declare the bean for your POJO along with its dependency on the request-scoped bean:

<bean id="myPojo">
  <property name="myAttr" ref="myAttr"/>
</bean>

See: Request, session, and global session scopes

Spring should take care of all the details...

Upvotes: 1

Related Questions