//加载DispatcherServlet.properties内容,里面包含了很多Dispatcher的策略方法实现。这里不展开 static { // Load default strategy implementations from properties file. // This is currently strictly internal and not meant to be customized // by application developers. try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { thrownew IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage()); } }
/** * Create a new {@code DispatcherServlet} that will create its own internal web * application context based on defaults and values provided through servlet * init-params. Typically used in Servlet 2.5 or earlier environments, where the only * option for servlet registration is through {@code web.xml} which requires the use * of a no-arg constructor. * <p>Calling {@link #setContextConfigLocation} (init-param 'contextConfigLocation') * will dictate which XML files will be loaded by the * {@linkplain #DEFAULT_CONTEXT_CLASS default XmlWebApplicationContext} * <p>Calling {@link #setContextClass} (init-param 'contextClass') overrides the * default {@code XmlWebApplicationContext} and allows for specifying an alternative class, * such as {@code AnnotationConfigWebApplicationContext}. * <p>Calling {@link #setContextInitializerClasses} (init-param 'contextInitializerClasses') * indicates which {@code ApplicationContextInitializer} classes should be used to * further configure the internal application context prior to refresh(). * @see #DispatcherServlet(WebApplicationContext) */ publicDispatcherServlet(){ //上面这些是解释,核心一句话 @see #DispatcherServlet(WebApplicationContext) super(); setDispatchOptionsRequest(true); } /** * Create a new {@code DispatcherServlet} with the given web application context. This * constructor is useful in Servlet 3.0+ environments where instance-based registration * of servlets is possible through the {@link ServletContext#addServlet} API. * <p>Using this constructor indicates that the following properties / init-params * will be ignored: * <ul> * <li>{@link #setContextClass(Class)} / 'contextClass'</li> * <li>{@link #setContextConfigLocation(String)} / 'contextConfigLocation'</li> * <li>{@link #setContextAttribute(String)} / 'contextAttribute'</li> * <li>{@link #setNamespace(String)} / 'namespace'</li> * </ul> * <p>The given web application context may or may not yet be {@linkplain * ConfigurableApplicationContext#refresh() refreshed}. If it has <strong>not</strong> * already been refreshed (the recommended approach), then the following will occur: * <ul> * <li>If the given context does not already have a {@linkplain * ConfigurableApplicationContext#setParent parent}, the root application context * will be set as the parent.</li> * <li>If the given context has not already been assigned an {@linkplain * ConfigurableApplicationContext#setId id}, one will be assigned to it</li> * <li>{@code ServletContext} and {@code ServletConfig} objects will be delegated to * the application context</li> * <li>{@link #postProcessWebApplicationContext} will be called</li> * <li>Any {@code ApplicationContextInitializer}s specified through the * "contextInitializerClasses" init-param or through the {@link * #setContextInitializers} property will be applied.</li> * <li>{@link ConfigurableApplicationContext#refresh refresh()} will be called if the * context implements {@link ConfigurableApplicationContext}</li> * </ul> * If the context has already been refreshed, none of the above will occur, under the * assumption that the user has performed these actions (or not) per their specific * needs. * <p>See {@link org.springframework.web.WebApplicationInitializer} for usage examples. * @param webApplicationContext the context to use * @see #initWebApplicationContext * @see #configureAndRefreshWebApplicationContext * @see org.springframework.web.WebApplicationInitializer */ publicDispatcherServlet(WebApplicationContext webApplicationContext){ //这个Context应该就是Spring相关的Conext,下面会有关于WebApplicationContext的源码 //他是调用父类的构造函数去实现的这个地方。我们就一起看看它的父类 super(webApplicationContext); setDispatchOptionsRequest(true); }
/** * Create a new {@code FrameworkServlet} with the given web application context. This * constructor is useful in Servlet 3.0+ environments where instance-based registration * of servlets is possible through the {@link ServletContext#addServlet} API. * <p>Using this constructor indicates that the following properties / init-params * will be ignored: * <ul> * <li>{@link #setContextClass(Class)} / 'contextClass'</li> * <li>{@link #setContextConfigLocation(String)} / 'contextConfigLocation'</li> * <li>{@link #setContextAttribute(String)} / 'contextAttribute'</li> * <li>{@link #setNamespace(String)} / 'namespace'</li> * </ul> * <p>The given web application context may or may not yet be {@linkplain * ConfigurableApplicationContext#refresh() refreshed}. If it (a) is an implementation * of {@link ConfigurableWebApplicationContext} and (b) has <strong>not</strong> * already been refreshed (the recommended approach), then the following will occur: * <ul> * <li>If the given context does not already have a {@linkplain * ConfigurableApplicationContext#setParent parent}, the root application context * will be set as the parent.</li> * <li>If the given context has not already been assigned an {@linkplain * ConfigurableApplicationContext#setId id}, one will be assigned to it</li> * <li>{@code ServletContext} and {@code ServletConfig} objects will be delegated to * the application context</li> * <li>{@link #postProcessWebApplicationContext} will be called</li> * <li>Any {@link ApplicationContextInitializer}s specified through the * "contextInitializerClasses" init-param or through the {@link * #setContextInitializers} property will be applied.</li> * <li>{@link ConfigurableApplicationContext#refresh refresh()} will be called</li> * </ul> * If the context has already been refreshed or does not implement * {@code ConfigurableWebApplicationContext}, none of the above will occur under the * assumption that the user has performed these actions (or not) per his or her * specific needs. * <p>See {@link org.springframework.web.WebApplicationInitializer} for usage examples. * @param webApplicationContext the context to use * @see #initWebApplicationContext * @see #configureAndRefreshWebApplicationContext * @see org.springframework.web.WebApplicationInitializer */ publicFrameworkServlet(WebApplicationContext webApplicationContext){ this.webApplicationContext = webApplicationContext; }
protectedvoidconfigureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac){ if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // The application context id is still set to its original default value // -> assign a more useful id based on available information if (this.contextId != null) { wac.setId(this.contextId); } else { // Generate default id... wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName()); } }
wac.setServletContext(getServletContext()); wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// The wac environment's #initPropertySources will be called in any case when the context // is refreshed; do it eagerly here to ensure servlet property sources are in place for // use in any post-processing or initialization that occurs below prior to #refresh ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig()); }
/** * Initialize and publish the WebApplicationContext for this servlet. * <p>Delegates to {@link #createWebApplicationContext} for actual creation * of the context. Can be overridden in subclasses. * @return the WebApplicationContext instance * @see #FrameworkServlet(WebApplicationContext) * @see #setContextClass * @see #setContextConfigLocation */ protected WebApplicationContext initWebApplicationContext(){ WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null;
if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { // The context has not yet been refreshed -> provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() == null) { // The context instance was injected without an explicit parent -> set // the root application context (if any; may be null) as the parent cwac.setParent(rootContext); } configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { // No context instance was injected at construction time -> see if one // has been registered in the servlet context. If one exists, it is assumed // that the parent context (if any) has already been set and that the // user has performed any initialization such as setting the context id wac = findWebApplicationContext(); } if (wac == null) { // No context instance is defined for this servlet -> create a local one wac = createWebApplicationContext(rootContext); }
if (!this.refreshEventReceived) { // Either the context is not a ConfigurableApplicationContext with refresh // support or the context injected at construction time had already been // refreshed -> trigger initial onRefresh manually here. onRefresh(wac); }
if (this.publishContext) { // Publish the context as a servlet context attribute. String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } }
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent){ Class<?> contextClass = getContextClass(); if (this.logger.isDebugEnabled()) { this.logger.debug("Servlet with name '" + getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]"); } if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { thrownew ApplicationContextException( "Fatal initialization error in servlet with name '" + getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext"); } ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
/** * Subclasses may override this to perform custom initialization. * All bean properties of this servlet will have been set before this * method is invoked. * <p>This default implementation is empty. * @throws ServletException if subclass initialization fails */ protectedvoidinitServletBean()throws ServletException { } //用于给子类重写方法的钩子