Add `createDispatcherServlet` hook point

Add an extra hook point in `AbstractDispatcherServletInitializer` to
customize the `DispatcherServlet`.

Issue: SPR-13222
This commit is contained in:
Stephane Nicoll 2015-07-13 14:43:06 +02:00
parent 84138abfd1
commit d738dddd8f
4 changed files with 32 additions and 6 deletions

View File

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -53,6 +53,7 @@ import org.springframework.web.servlet.DispatcherServlet;
* @author Chris Beams * @author Chris Beams
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Stephane Nicoll
* @since 3.2 * @since 3.2
*/ */
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer { public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {
@ -76,7 +77,8 @@ public abstract class AbstractDispatcherServletInitializer extends AbstractConte
* from {@link #createServletApplicationContext()}, and mapping it to the patterns * from {@link #createServletApplicationContext()}, and mapping it to the patterns
* returned from {@link #getServletMappings()}. * returned from {@link #getServletMappings()}.
* <p>Further customization can be achieved by overriding {@link * <p>Further customization can be achieved by overriding {@link
* #customizeRegistration(ServletRegistration.Dynamic)}. * #customizeRegistration(ServletRegistration.Dynamic)} or
* {@link #createDispatcherServlet(WebApplicationContext)}.
* @param servletContext the context to register the servlet against * @param servletContext the context to register the servlet against
*/ */
protected void registerDispatcherServlet(ServletContext servletContext) { protected void registerDispatcherServlet(ServletContext servletContext) {
@ -88,7 +90,7 @@ public abstract class AbstractDispatcherServletInitializer extends AbstractConte
"createServletApplicationContext() did not return an application " + "createServletApplicationContext() did not return an application " +
"context for servlet [" + servletName + "]"); "context for servlet [" + servletName + "]");
DispatcherServlet dispatcherServlet = new DispatcherServlet(servletAppContext); DispatcherServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers()); dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
@ -129,6 +131,13 @@ public abstract class AbstractDispatcherServletInitializer extends AbstractConte
*/ */
protected abstract WebApplicationContext createServletApplicationContext(); protected abstract WebApplicationContext createServletApplicationContext();
/**
* Create a {@link DispatcherServlet} with the specified {@link WebApplicationContext}.
*/
protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
return new DispatcherServlet(servletAppContext);
}
/** /**
* Specify application context initializers to be applied to the servlet-specific * Specify application context initializers to be applied to the servlet-specific
* application context that the {@code DispatcherServlet} is being created with. * application context that the {@code DispatcherServlet} is being created with.

View File

@ -1,11 +1,11 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -70,6 +70,7 @@ public class DispatcherServletInitializerTests {
assertNotNull(servlets.get(SERVLET_NAME)); assertNotNull(servlets.get(SERVLET_NAME));
DispatcherServlet servlet = (DispatcherServlet) servlets.get(SERVLET_NAME); DispatcherServlet servlet = (DispatcherServlet) servlets.get(SERVLET_NAME);
assertEquals(MyDispatcherServlet.class, servlet.getClass());
WebApplicationContext servletContext = servlet.getWebApplicationContext(); WebApplicationContext servletContext = servlet.getWebApplicationContext();
assertTrue(servletContext.containsBean("bean")); assertTrue(servletContext.containsBean("bean"));
@ -84,6 +85,7 @@ public class DispatcherServletInitializerTests {
assertEquals(ROLE_NAME, registration.getRunAsRole()); assertEquals(ROLE_NAME, registration.getRunAsRole());
} }
private class MyMockServletContext extends MockServletContext { private class MyMockServletContext extends MockServletContext {
@Override @Override
@ -104,6 +106,11 @@ public class DispatcherServletInitializerTests {
return SERVLET_NAME; return SERVLET_NAME;
} }
@Override
protected DispatcherServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
return new MyDispatcherServlet(servletAppContext);
}
@Override @Override
protected WebApplicationContext createServletApplicationContext() { protected WebApplicationContext createServletApplicationContext() {
StaticWebApplicationContext servletContext = StaticWebApplicationContext servletContext =
@ -129,7 +136,12 @@ public class DispatcherServletInitializerTests {
} }
private static class MyBean { private static class MyBean {
}
private static class MyDispatcherServlet extends DispatcherServlet {
public MyDispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
}
} }
} }

View File

@ -205,7 +205,7 @@ based equivalent of the above `web.xml` example:
`WebApplicationInitializer` is an interface provided by Spring MVC that ensures your `WebApplicationInitializer` is an interface provided by Spring MVC that ensures your
code-based configuration is detected and automatically used to initialize any Servlet 3 code-based configuration is detected and automatically used to initialize any Servlet 3
container. An abstract base class implementation of this interace named container. An abstract base class implementation of this interface named
`AbstractDispatcherServletInitializer` makes it even easier to register the `AbstractDispatcherServletInitializer` makes it even easier to register the
`DispatcherServlet` by simply specifying its servlet mapping. `DispatcherServlet` by simply specifying its servlet mapping.
See <<mvc-container-config,Code-based Servlet container initialization>> for more details. See <<mvc-container-config,Code-based Servlet container initialization>> for more details.
@ -4462,6 +4462,9 @@ The `isAsyncSupported` protected method of `AbstractDispatcherServletInitializer
provides a single place to enable async support on the `DispatcherServlet` and all provides a single place to enable async support on the `DispatcherServlet` and all
filters mapped to it. By default this flag is set to `true`. filters mapped to it. By default this flag is set to `true`.
Finally, if you need to further customize the `DispatcherServlet` itself, you can
override the `createDispatcherServlet` method.

View File

@ -525,6 +525,8 @@ public @interface MyTestConfig {
* When using GSON or Jackson 2.6+, the handler method return type is used to improve * When using GSON or Jackson 2.6+, the handler method return type is used to improve
serialization of parameterized types like `List<Foo>`. serialization of parameterized types like `List<Foo>`.
* Default JSON prefix has been changed from "{} && " to the safer ")]}', " one. * Default JSON prefix has been changed from "{} && " to the safer ")]}', " one.
* Protected `createDispatcherServlet` method in `AbstractDispatcherServletInitializer` to further
customize the `DispatcherServlet` instance to use.
=== WebSocket Messaging Improvements === WebSocket Messaging Improvements