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