001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web;
018
019import javax.servlet.ServletContext;
020import javax.servlet.ServletException;
021
022/**
023 * Interface to be implemented in Servlet 3.0+ environments in order to configure the
024 * {@link ServletContext} programmatically -- as opposed to (or possibly in conjunction
025 * with) the traditional {@code web.xml}-based approach.
026 *
027 * <p>Implementations of this SPI will be detected automatically by {@link
028 * SpringServletContainerInitializer}, which itself is bootstrapped automatically
029 * by any Servlet 3.0 container. See {@linkplain SpringServletContainerInitializer its
030 * Javadoc} for details on this bootstrapping mechanism.
031 *
032 * <h2>Example</h2>
033 * <h3>The traditional, XML-based approach</h3>
034 * Most Spring users building a web application will need to register Spring's {@code
035 * DispatcherServlet}. For reference, in WEB-INF/web.xml, this would typically be done as
036 * follows:
037 * <pre class="code">
038 * &lt;servlet&gt;
039 *   &lt;servlet-name>dispatcher&lt;/servlet-name&gt;
040 *   &lt;servlet-class&gt;
041 *     org.springframework.web.servlet.DispatcherServlet
042 *   &lt;/servlet-class&gt;
043 *   &lt;init-param>
044 *     &lt;param-name>contextConfigLocation&lt;/param-name&gt;
045 *     &lt;param-value>/WEB-INF/spring/dispatcher-config.xml&lt;/param-value&gt;
046 *   &lt;/init-param&gt;
047 *   &lt;load-on-startup>1&lt;/load-on-startup&gt;
048 * &lt;/servlet&gt;
049 *
050 * &lt;servlet-mapping&gt;
051 *   &lt;servlet-name&gt;dispatcher&lt;/servlet-name&gt;
052 *   &lt;url-pattern&gt;/&lt;/url-pattern&gt;
053 * &lt;/servlet-mapping&gt;</pre>
054 *
055 * <h3>The code-based approach with {@code WebApplicationInitializer}</h3>
056 * Here is the equivalent {@code DispatcherServlet} registration logic,
057 * {@code WebApplicationInitializer}-style:
058 * <pre class="code">
059 * public class MyWebAppInitializer implements WebApplicationInitializer {
060 *
061 *    &#064;Override
062 *    public void onStartup(ServletContext container) {
063 *      XmlWebApplicationContext appContext = new XmlWebApplicationContext();
064 *      appContext.setConfigLocation("/WEB-INF/spring/dispatcher-config.xml");
065 *
066 *      ServletRegistration.Dynamic dispatcher =
067 *        container.addServlet("dispatcher", new DispatcherServlet(appContext));
068 *      dispatcher.setLoadOnStartup(1);
069 *      dispatcher.addMapping("/");
070 *    }
071 *
072 * }</pre>
073 *
074 * As an alternative to the above, you can also extend from {@link
075 * org.springframework.web.servlet.support.AbstractDispatcherServletInitializer}.
076 *
077 * As you can see, thanks to Servlet 3.0's new {@link ServletContext#addServlet} method
078 * we're actually registering an <em>instance</em> of the {@code DispatcherServlet}, and
079 * this means that the {@code DispatcherServlet} can now be treated like any other object
080 * -- receiving constructor injection of its application context in this case.
081 *
082 * <p>This style is both simpler and more concise. There is no concern for dealing with
083 * init-params, etc, just normal JavaBean-style properties and constructor arguments. You
084 * are free to create and work with your Spring application contexts as necessary before
085 * injecting them into the {@code DispatcherServlet}.
086 *
087 * <p>Most major Spring Web components have been updated to support this style of
088 * registration.  You'll find that {@code DispatcherServlet}, {@code FrameworkServlet},
089 * {@code ContextLoaderListener} and {@code DelegatingFilterProxy} all now support
090 * constructor arguments. Even if a component (e.g. non-Spring, other third party) has not
091 * been specifically updated for use within {@code WebApplicationInitializers}, they still
092 * may be used in any case. The Servlet 3.0 {@code ServletContext} API allows for setting
093 * init-params, context-params, etc programmatically.
094 *
095 * <h2>A 100% code-based approach to configuration</h2>
096 * In the example above, {@code WEB-INF/web.xml} was successfully replaced with code in
097 * the form of a {@code WebApplicationInitializer}, but the actual
098 * {@code dispatcher-config.xml} Spring configuration remained XML-based.
099 * {@code WebApplicationInitializer} is a perfect fit for use with Spring's code-based
100 * {@code @Configuration} classes. See @{@link
101 * org.springframework.context.annotation.Configuration Configuration} Javadoc for
102 * complete details, but the following example demonstrates refactoring to use Spring's
103 * {@link org.springframework.web.context.support.AnnotationConfigWebApplicationContext
104 * AnnotationConfigWebApplicationContext} in lieu of {@code XmlWebApplicationContext}, and
105 * user-defined {@code @Configuration} classes {@code AppConfig} and
106 * {@code DispatcherConfig} instead of Spring XML files. This example also goes a bit
107 * beyond those above to demonstrate typical configuration of the 'root' application
108 * context and registration of the {@code ContextLoaderListener}:
109 * <pre class="code">
110 * public class MyWebAppInitializer implements WebApplicationInitializer {
111 *
112 *    &#064;Override
113 *    public void onStartup(ServletContext container) {
114 *      // Create the 'root' Spring application context
115 *      AnnotationConfigWebApplicationContext rootContext =
116 *        new AnnotationConfigWebApplicationContext();
117 *      rootContext.register(AppConfig.class);
118 *
119 *      // Manage the lifecycle of the root application context
120 *      container.addListener(new ContextLoaderListener(rootContext));
121 *
122 *      // Create the dispatcher servlet's Spring application context
123 *      AnnotationConfigWebApplicationContext dispatcherContext =
124 *        new AnnotationConfigWebApplicationContext();
125 *      dispatcherContext.register(DispatcherConfig.class);
126 *
127 *      // Register and map the dispatcher servlet
128 *      ServletRegistration.Dynamic dispatcher =
129 *        container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
130 *      dispatcher.setLoadOnStartup(1);
131 *      dispatcher.addMapping("/");
132 *    }
133 *
134 * }</pre>
135 *
136 * As an alternative to the above, you can also extend from {@link
137 * org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer}.
138 *
139 * Remember that {@code WebApplicationInitializer} implementations are <em>detected
140 * automatically</em> -- so you are free to package them within your application as you
141 * see fit.
142 *
143 * <h2>Ordering {@code WebApplicationInitializer} execution</h2>
144 * {@code WebApplicationInitializer} implementations may optionally be annotated at the
145 * class level with Spring's @{@link org.springframework.core.annotation.Order Order}
146 * annotation or may implement Spring's {@link org.springframework.core.Ordered Ordered}
147 * interface. If so, the initializers will be ordered prior to invocation. This provides
148 * a mechanism for users to ensure the order in which servlet container initialization
149 * occurs. Use of this feature is expected to be rare, as typical applications will likely
150 * centralize all container initialization within a single {@code WebApplicationInitializer}.
151 *
152 * <h2>Caveats</h2>
153 *
154 * <h3>web.xml versioning</h3>
155 * <p>{@code WEB-INF/web.xml} and {@code WebApplicationInitializer} use are not mutually
156 * exclusive; for example, web.xml can register one servlet, and a {@code
157 * WebApplicationInitializer} can register another. An initializer can even
158 * <em>modify</em> registrations performed in {@code web.xml} through methods such as
159 * {@link ServletContext#getServletRegistration(String)}. <strong>However, if
160 * {@code WEB-INF/web.xml} is present in the application, its {@code version} attribute
161 * must be set to "3.0" or greater, otherwise {@code ServletContainerInitializer}
162 * bootstrapping will be ignored by the servlet container.</strong>
163 *
164 * <h3>Mapping to '/' under Tomcat</h3>
165 * <p>Apache Tomcat maps its internal {@code DefaultServlet} to "/", and on Tomcat versions
166 * &lt;= 7.0.14, this servlet mapping <em>cannot be overridden programmatically</em>.
167 * 7.0.15 fixes this issue. Overriding the "/" servlet mapping has also been tested
168 * successfully under GlassFish 3.1.<p>
169 *
170 * @author Chris Beams
171 * @since 3.1
172 * @see SpringServletContainerInitializer
173 * @see org.springframework.web.context.AbstractContextLoaderInitializer
174 * @see org.springframework.web.servlet.support.AbstractDispatcherServletInitializer
175 * @see org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer
176 */
177public interface WebApplicationInitializer {
178
179        /**
180         * Configure the given {@link ServletContext} with any servlets, filters, listeners
181         * context-params and attributes necessary for initializing this web application. See
182         * examples {@linkplain WebApplicationInitializer above}.
183         * @param servletContext the {@code ServletContext} to initialize
184         * @throws ServletException if any call against the given {@code ServletContext}
185         * throws a {@code ServletException}
186         */
187        void onStartup(ServletContext servletContext) throws ServletException;
188
189}