Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make Spring 3.2 Async Servlet-Filter defined in Java Config..without having web.xml

Using latest and greatest Spring 3.2.3, Tomcat 7.0.42, Servlet 3.0 container, Java 7. We need to do JSONP for our response, so we implement that by doing a Servlet Filter just like this:

http://jpgmr.wordpress.com/2010/07/28/tutorial-implementing-a-servlet-filter-for-jsonp-callback-with-springs-delegatingfilterproxy/

but without the web.xml currently..we are using Java Annotation Config.

In our @Controller, we are returning a DeferredResult<String>, and then in our @Service, which is called by our @Controller, we have the @Async annotation. The reason we went the @Async route (not the AysncContext route) was because this is a "fire and forget" type async operation. But I do need to return some JSON that says the operation has begun to the requestor.

@RequestMapping(method = RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public DeferredResult<String> testing(@RequestParam(value="submit", required=true) String param)
{
            final DeferredResult<String> result = new DeferredResult<String>();
            service.doIt(param, result);

            return result;
}

And in our @Service

@Async
public DeferredResult<String> doIt(String param2, DeferredResult<String> result)
{
    log.info("Calling Async doIt Method");
    result.setResult("{hello:there}");
}

I'm stuck...I'm trying to figure out if there is a way add async-supported tag for a Servlet Filter in a Java Config? I base that on seeing this presentation (slide 28):

http://rstoyanchev.github.io/spring-mvc-32-update/#28

Some other info:

Have @EnableAsync on the Configuration, and we are using the AbstractAnnotationConfigDispatcherServletInitializer to define our application, but I can't seem to figure out how to tell that to use have async filters (just using the getServletFilters() to return our JsonpFilter).

Basically what is happening is that the JSONP filter is "wrapping" nothing...but I do see the Filter called a second time, after the result has been set in the TaskExecutor thread..but at that point the response has already gone out...so, I see the filter "get Data" twice..once right when the @Controller method exits, and then a second time right after the DeferredResult.setResult() has been set.

We also tried this as well on our Filter class:

@WebFilter(urlPatterns = "/*", asyncSupported = true)

but that to did not work (even looked like it even made 2 separate filters according to the logs..but, could I be wrong there about that).

We could switch to a Callable if we need to..that's not a big deal. I did see that there was some differences between DeferredResult and Callable with regards to what threads Spring knows about.

If the answer is that you need to use web.xml, any really good way to do a Java Config with web.xml hybrid?

EDIT 1:

Based on reading a few different resources I found a couple of things:

  1. From: Spring Aync Preview Blog

Servlet Filters

*All Spring Framework Servlet filter implementations have been modified as necessary to work in asynchronous request processing. As for any other filters, some will work — typically those that do pre-processing, and others will need to be modified — typically those that do post-processing at the end of a request. Such filters will need to recognize when the initial Servlet container thread is being exited, making way for another thread to continue processing, and when they are invoked as part of an asynchronous dispatch to complete processing.**

  1. From the Spring MVC Ref. docs, I actually RTFM'd:

The sequence of events for async request processing with a DeferredResult is the same in principle except it's up to the application to produce the asynchronous result from some thread: (1) Controller returns a DeferredResult and saves it in some in-memory queue or list where it can be accessed, (2) Spring MVC starts async processing, (3) the DispatcherServlet and all configured Filter's exit the request processing thread but the response remains open, (4) the application sets theDeferredResult from some thread and Spring MVC dispatches the request back to the Servlet container, (5) the DispatcherServlet is invoked again and processing resumes with the asynchronously produced result.

So, basically, i knew/know that the separate thread would be calling the filter...that's not what has been hanging me up..it was how to figure out if the filter should modify the response...and you can't look at the size of the data, because a 0 bytes could be a correct "answer."

So, I now only write if the DispatchType = ASYNC

Not really sure this is correct to do long term..but, it does seem to fix the problem.

Any other suggestions/ideas?

like image 215
Aaron G Avatar asked Mar 24 '23 02:03

Aaron G


1 Answers

It seems if you're extending AbstractAnnotationConfigDispatcherServletInitializer, you can override this method and set async support:

@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
    registration.setInitParameter("dispatchOptionsRequest", "true");
    registration.setAsyncSupported(true);
}
like image 200
Bal Avatar answered Apr 06 '23 03:04

Bal