Add config options for MVC async interceptors
The MVC namespace and the MVC Java config now allow configuring CallableProcessingInterceptor and DeferredResultProcessingInterceptor instances. Issue: SPR-9914
This commit is contained in:
@@ -174,6 +174,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, source, parserContext);
|
||||
String asyncTimeout = getAsyncTimeout(element, source, parserContext);
|
||||
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element, source, parserContext);
|
||||
ManagedList<?> callableInterceptors = getCallableInterceptors(element, source, parserContext);
|
||||
ManagedList<?> deferredResultInterceptors = getDeferredResultInterceptors(element, source, parserContext);
|
||||
|
||||
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
|
||||
handlerAdapterDef.setSource(source);
|
||||
@@ -197,6 +199,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
if (asyncExecutor != null) {
|
||||
handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
|
||||
}
|
||||
handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
|
||||
handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
|
||||
String handlerAdapterName = parserContext.getReaderContext().registerWithGeneratedName(handlerAdapterDef);
|
||||
|
||||
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
|
||||
@@ -337,6 +341,40 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ManagedList<?> getCallableInterceptors(Element element, Object source, ParserContext parserContext) {
|
||||
ManagedList<? super Object> interceptors = new ManagedList<Object>();
|
||||
Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support");
|
||||
if (asyncElement != null) {
|
||||
Element interceptorsElement = DomUtils.getChildElementByTagName(asyncElement, "callable-interceptors");
|
||||
if (interceptorsElement != null) {
|
||||
interceptors.setSource(source);
|
||||
for (Element converter : DomUtils.getChildElementsByTagName(interceptorsElement, "bean")) {
|
||||
BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(converter);
|
||||
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(converter, beanDef);
|
||||
interceptors.add(beanDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
return interceptors;
|
||||
}
|
||||
|
||||
private ManagedList<?> getDeferredResultInterceptors(Element element, Object source, ParserContext parserContext) {
|
||||
ManagedList<? super Object> interceptors = new ManagedList<Object>();
|
||||
Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support");
|
||||
if (asyncElement != null) {
|
||||
Element interceptorsElement = DomUtils.getChildElementByTagName(asyncElement, "deferred-result-interceptors");
|
||||
if (interceptorsElement != null) {
|
||||
interceptors.setSource(source);
|
||||
for (Element converter : DomUtils.getChildElementsByTagName(interceptorsElement, "bean")) {
|
||||
BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(converter);
|
||||
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(converter, beanDef);
|
||||
interceptors.add(beanDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
return interceptors;
|
||||
}
|
||||
|
||||
private ManagedList<?> getArgumentResolvers(Element element, Object source, ParserContext parserContext) {
|
||||
Element resolversElement = DomUtils.getChildElementByTagName(element, "argument-resolvers");
|
||||
if (resolversElement != null) {
|
||||
|
||||
@@ -15,11 +15,18 @@
|
||||
*/
|
||||
package org.springframework.web.servlet.config.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.async.AsyncTask;
|
||||
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
|
||||
|
||||
/**
|
||||
* Helps with configuring a options for asynchronous request processing.
|
||||
@@ -33,6 +40,13 @@ public class AsyncSupportConfigurer {
|
||||
|
||||
private Long timeout;
|
||||
|
||||
private final List<CallableProcessingInterceptor> callableInterceptors =
|
||||
new ArrayList<CallableProcessingInterceptor>();
|
||||
|
||||
private final List<DeferredResultProcessingInterceptor> deferredResultInterceptors =
|
||||
new ArrayList<DeferredResultProcessingInterceptor>();
|
||||
|
||||
|
||||
/**
|
||||
* Set the default {@link AsyncTaskExecutor} to use when a controller method
|
||||
* returns a {@link Callable}. Controller methods can override this default on
|
||||
@@ -64,6 +78,31 @@ public class AsyncSupportConfigurer {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure lifecycle intercepters with callbacks around concurrent request
|
||||
* execution that starts when a controller returns a
|
||||
* {@link java.util.concurrent.Callable}.
|
||||
*
|
||||
* @param interceptors the interceptors to register
|
||||
*/
|
||||
public AsyncSupportConfigurer registerCallableInterceptors(CallableProcessingInterceptor... interceptors) {
|
||||
Assert.notNull(interceptors, "Interceptors are required");
|
||||
this.callableInterceptors.addAll(Arrays.asList(interceptors));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure lifecycle intercepters with callbacks around concurrent request
|
||||
* execution that starts when a controller returns a {@link DeferredResult}.
|
||||
*
|
||||
* @param interceptors the interceptors to register
|
||||
*/
|
||||
public AsyncSupportConfigurer registerDeferredResultInterceptors(DeferredResultProcessingInterceptor... interceptors) {
|
||||
Assert.notNull(interceptors, "Interceptors are required");
|
||||
this.deferredResultInterceptors.addAll(Arrays.asList(interceptors));
|
||||
return this;
|
||||
}
|
||||
|
||||
protected AsyncTaskExecutor getTaskExecutor() {
|
||||
return this.taskExecutor;
|
||||
}
|
||||
@@ -72,4 +111,12 @@ public class AsyncSupportConfigurer {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
protected List<CallableProcessingInterceptor> getCallableInterceptors() {
|
||||
return this.callableInterceptors;
|
||||
}
|
||||
|
||||
protected List<DeferredResultProcessingInterceptor> getDeferredResultInterceptors() {
|
||||
return this.deferredResultInterceptors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -378,6 +378,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
||||
if (configurer.getTimeout() != null) {
|
||||
adapter.setAsyncRequestTimeout(configurer.getTimeout());
|
||||
}
|
||||
adapter.setCallableInterceptors(configurer.getCallableInterceptors());
|
||||
adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
@@ -64,6 +65,8 @@ import org.springframework.web.context.request.ServletWebRequest;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.context.request.async.AsyncTask;
|
||||
import org.springframework.web.context.request.async.AsyncWebRequest;
|
||||
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
|
||||
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
|
||||
import org.springframework.web.context.request.async.WebAsyncManager;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
import org.springframework.web.method.ControllerAdviceBean;
|
||||
@@ -135,6 +138,12 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
|
||||
|
||||
private Long asyncRequestTimeout;
|
||||
|
||||
private final Map<Object, CallableProcessingInterceptor> callableInterceptors =
|
||||
new LinkedHashMap<Object, CallableProcessingInterceptor>();
|
||||
|
||||
private final Map<Object, DeferredResultProcessingInterceptor> deferredResultInterceptors =
|
||||
new LinkedHashMap<Object, DeferredResultProcessingInterceptor>();
|
||||
|
||||
private boolean ignoreDefaultModelOnRedirect = false;
|
||||
|
||||
private int cacheSecondsForSessionAttributeHandlers = 0;
|
||||
@@ -363,6 +372,34 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
|
||||
this.asyncRequestTimeout = timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure {@code CallableProcessingInterceptor}'s to register on async requests.
|
||||
* @param interceptors the interceptors to register
|
||||
*/
|
||||
public void setCallableInterceptors(List<CallableProcessingInterceptor> interceptors) {
|
||||
Assert.notNull(interceptors);
|
||||
for (int index = 0 ; index < interceptors.size(); index++) {
|
||||
CallableProcessingInterceptor interceptor = interceptors.get(index);
|
||||
this.callableInterceptors.put(getInterceptorKey(interceptor, index), interceptor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure {@code DeferredResultProcessingInterceptor}'s to register on async requests.
|
||||
* @param interceptors the interceptors to register
|
||||
*/
|
||||
public void setDeferredResultInterceptors(List<DeferredResultProcessingInterceptor> interceptors) {
|
||||
Assert.notNull(interceptors);
|
||||
for (int index = 0 ; index < interceptors.size(); index++) {
|
||||
DeferredResultProcessingInterceptor interceptor = interceptors.get(index);
|
||||
this.deferredResultInterceptors.put(getInterceptorKey(interceptor, index), interceptor);
|
||||
}
|
||||
}
|
||||
|
||||
private String getInterceptorKey(Object interceptor, int index) {
|
||||
return this.hashCode() + ":" + interceptor.getClass().getName() + "#" + index;
|
||||
}
|
||||
|
||||
/**
|
||||
* By default the content of the "default" model is used both during
|
||||
* rendering and redirect scenarios. Alternatively a controller method
|
||||
@@ -703,6 +740,8 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
|
||||
final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
||||
asyncManager.setTaskExecutor(this.taskExecutor);
|
||||
asyncManager.setAsyncWebRequest(asyncWebRequest);
|
||||
asyncManager.registerAllCallableInterceptors(this.callableInterceptors);
|
||||
asyncManager.registerAllDeferredResultInterceptors(this.deferredResultInterceptors);
|
||||
|
||||
if (asyncManager.hasConcurrentResult()) {
|
||||
Object result = asyncManager.getConcurrentResult();
|
||||
|
||||
Reference in New Issue
Block a user