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 * <servlet> 039 * <servlet-name>dispatcher</servlet-name> 040 * <servlet-class> 041 * org.springframework.web.servlet.DispatcherServlet 042 * </servlet-class> 043 * <init-param> 044 * <param-name>contextConfigLocation</param-name> 045 * <param-value>/WEB-INF/spring/dispatcher-config.xml</param-value> 046 * </init-param> 047 * <load-on-startup>1</load-on-startup> 048 * </servlet> 049 * 050 * <servlet-mapping> 051 * <servlet-name>dispatcher</servlet-name> 052 * <url-pattern>/</url-pattern> 053 * </servlet-mapping></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 * @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 * @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 * <= 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}