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 * @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 * @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 * <= 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}