/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.servlet.support;

import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.FilterRegistration.Dynamic;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.Conventions;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.AbstractContextLoaderInitializer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;

Base class for WebApplicationInitializer implementations that register a DispatcherServlet in the servlet context.

Most applications should consider extending the Spring Java config subclass AbstractAnnotationConfigDispatcherServletInitializer.

Author:Arjen Poutsma, Chris Beams, Rossen Stoyanchev, Juergen Hoeller, Stephane Nicoll
Since:3.2
/** * Base class for {@link org.springframework.web.WebApplicationInitializer} * implementations that register a {@link DispatcherServlet} in the servlet context. * * <p>Most applications should consider extending the Spring Java config subclass * {@link AbstractAnnotationConfigDispatcherServletInitializer}. * * @author Arjen Poutsma * @author Chris Beams * @author Rossen Stoyanchev * @author Juergen Hoeller * @author Stephane Nicoll * @since 3.2 */
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {
The default servlet name. Can be customized by overriding getServletName.
/** * The default servlet name. Can be customized by overriding {@link #getServletName}. */
public static final String DEFAULT_SERVLET_NAME = "dispatcher"; @Override public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext); registerDispatcherServlet(servletContext); }
Register a DispatcherServlet against the given servlet context.

This method will create a DispatcherServlet with the name returned by getServletName(), initializing it with the application context returned from createServletApplicationContext(), and mapping it to the patterns returned from getServletMappings().

Further customization can be achieved by overriding customizeRegistration(Dynamic) or createDispatcherServlet(WebApplicationContext).

Params:
  • servletContext – the context to register the servlet against
/** * Register a {@link DispatcherServlet} against the given servlet context. * <p>This method will create a {@code DispatcherServlet} with the name returned by * {@link #getServletName()}, initializing it with the application context returned * from {@link #createServletApplicationContext()}, and mapping it to the patterns * returned from {@link #getServletMappings()}. * <p>Further customization can be achieved by overriding {@link * #customizeRegistration(ServletRegistration.Dynamic)} or * {@link #createDispatcherServlet(WebApplicationContext)}. * @param servletContext the context to register the servlet against */
protected void registerDispatcherServlet(ServletContext servletContext) { String servletName = getServletName(); Assert.hasLength(servletName, "getServletName() must not return null or empty"); WebApplicationContext servletAppContext = createServletApplicationContext(); Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null"); FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext); Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null"); dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers()); ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet); if (registration == null) { throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " + "Check if there is another servlet registered under the same name."); } registration.setLoadOnStartup(1); registration.addMapping(getServletMappings()); registration.setAsyncSupported(isAsyncSupported()); Filter[] filters = getServletFilters(); if (!ObjectUtils.isEmpty(filters)) { for (Filter filter : filters) { registerServletFilter(servletContext, filter); } } customizeRegistration(registration); }
Return the name under which the DispatcherServlet will be registered. Defaults to DEFAULT_SERVLET_NAME.
See Also:
/** * Return the name under which the {@link DispatcherServlet} will be registered. * Defaults to {@link #DEFAULT_SERVLET_NAME}. * @see #registerDispatcherServlet(ServletContext) */
protected String getServletName() { return DEFAULT_SERVLET_NAME; }
Create a servlet application context to be provided to the DispatcherServlet.

The returned context is delegated to Spring's DispatcherServlet(WebApplicationContext). As such, it typically contains controllers, view resolvers, locale resolvers, and other web-related beans.

See Also:
/** * Create a servlet application context to be provided to the {@code DispatcherServlet}. * <p>The returned context is delegated to Spring's * {@link DispatcherServlet#DispatcherServlet(WebApplicationContext)}. As such, * it typically contains controllers, view resolvers, locale resolvers, and other * web-related beans. * @see #registerDispatcherServlet(ServletContext) */
protected abstract WebApplicationContext createServletApplicationContext();
Create a DispatcherServlet (or other kind of FrameworkServlet-derived dispatcher) with the specified WebApplicationContext.

Note: This allows for any FrameworkServlet subclass as of 4.2.3. Previously, it insisted on returning a DispatcherServlet or subclass thereof.

/** * Create a {@link DispatcherServlet} (or other kind of {@link FrameworkServlet}-derived * dispatcher) with the specified {@link WebApplicationContext}. * <p>Note: This allows for any {@link FrameworkServlet} subclass as of 4.2.3. * Previously, it insisted on returning a {@link DispatcherServlet} or subclass thereof. */
protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) { return new DispatcherServlet(servletAppContext); }
Specify application context initializers to be applied to the servlet-specific application context that the DispatcherServlet is being created with.
See Also:
Since:4.2
/** * Specify application context initializers to be applied to the servlet-specific * application context that the {@code DispatcherServlet} is being created with. * @since 4.2 * @see #createServletApplicationContext() * @see DispatcherServlet#setContextInitializers * @see #getRootApplicationContextInitializers() */
@Nullable protected ApplicationContextInitializer<?>[] getServletApplicationContextInitializers() { return null; }
Specify the servlet mapping(s) for the DispatcherServlet — for example "/", "/app", etc.
See Also:
/** * Specify the servlet mapping(s) for the {@code DispatcherServlet} &mdash; * for example {@code "/"}, {@code "/app"}, etc. * @see #registerDispatcherServlet(ServletContext) */
protected abstract String[] getServletMappings();
Specify filters to add and map to the DispatcherServlet.
See Also:
Returns:an array of filters or null
/** * Specify filters to add and map to the {@code DispatcherServlet}. * @return an array of filters or {@code null} * @see #registerServletFilter(ServletContext, Filter) */
@Nullable protected Filter[] getServletFilters() { return null; }
Add the given filter to the ServletContext and map it to the DispatcherServlet as follows:
  • a default filter name is chosen based on its concrete type
  • the asyncSupported flag is set depending on the return value of asyncSupported
  • a filter mapping is created with dispatcher types REQUEST, FORWARD, INCLUDE, and conditionally ASYNC depending on the return value of asyncSupported

If the above defaults are not suitable or insufficient, override this method and register filters directly with the ServletContext.

Params:
  • servletContext – the servlet context to register filters with
  • filter – the filter to be registered
Returns:the filter registration
/** * Add the given filter to the ServletContext and map it to the * {@code DispatcherServlet} as follows: * <ul> * <li>a default filter name is chosen based on its concrete type * <li>the {@code asyncSupported} flag is set depending on the * return value of {@link #isAsyncSupported() asyncSupported} * <li>a filter mapping is created with dispatcher types {@code REQUEST}, * {@code FORWARD}, {@code INCLUDE}, and conditionally {@code ASYNC} depending * on the return value of {@link #isAsyncSupported() asyncSupported} * </ul> * <p>If the above defaults are not suitable or insufficient, override this * method and register filters directly with the {@code ServletContext}. * @param servletContext the servlet context to register filters with * @param filter the filter to be registered * @return the filter registration */
protected FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) { String filterName = Conventions.getVariableName(filter); Dynamic registration = servletContext.addFilter(filterName, filter); if (registration == null) { int counter = 0; while (registration == null) { if (counter == 100) { throw new IllegalStateException("Failed to register filter with name '" + filterName + "'. " + "Check if there is another filter registered under the same name."); } registration = servletContext.addFilter(filterName + "#" + counter, filter); counter++; } } registration.setAsyncSupported(isAsyncSupported()); registration.addMappingForServletNames(getDispatcherTypes(), false, getServletName()); return registration; } private EnumSet<DispatcherType> getDispatcherTypes() { return (isAsyncSupported() ? EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ASYNC) : EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE)); }
A single place to control the asyncSupported flag for the DispatcherServlet and all filters added via getServletFilters().

The default value is "true".

/** * A single place to control the {@code asyncSupported} flag for the * {@code DispatcherServlet} and all filters added via {@link #getServletFilters()}. * <p>The default value is "true". */
protected boolean isAsyncSupported() { return true; }
Optionally perform further registration customization once registerDispatcherServlet(ServletContext) has completed.
Params:
  • registration – the DispatcherServlet registration to be customized
See Also:
/** * Optionally perform further registration customization once * {@link #registerDispatcherServlet(ServletContext)} has completed. * @param registration the {@code DispatcherServlet} registration to be customized * @see #registerDispatcherServlet(ServletContext) */
protected void customizeRegistration(ServletRegistration.Dynamic registration) { } }