SpringMvc之启动流程
当⼀个Web应⽤部署到容器内时(eg.tomcat),在Web应⽤开始响应执⾏⽤户请求前,以下步骤会被依次执⾏:部署描述⽂件中(eg.tomcat的l)由<listener>元素标记的事件会被创建和初始化
对于所有事件,如果实现了ServletContextListener接⼝,将会执⾏其实现的contextInitialized()⽅法
部署描述⽂件中由<filter>元素标记的过滤器会被创建和初始化,并调⽤其init()⽅法
部署描述⽂件中由<servlet>元素标记的servlet会根据<load-on-startup>的权值按顺序创建和初始化,并调⽤其init()⽅法
通过上述官⽅⽂档的描述,可绘制如下Web应⽤部署初始化流程执⾏图。
可以发现,在tomcat下web应⽤的初始化流程是,先初始化listener接着初始化filter最后初始化servlet,当我们清楚认识到Web应⽤部署到容器后的初始化过程后,就可以进⼀步深⼊探讨SpringMVC的启动过程。
Spring MVC启动过程
接下来以⼀个常见的简单l配置进⾏Spring MVC启动过程的分析,l配置内容如下:
<web-app>
<display-name>Web Application</display-name>
<!--全局变量配置-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-*.xml</param-value>
</context-param>
<!---->
<listener>
<listener-class>org.t.ContextLoaderListener</listener-class>
</listener>
<!--解决乱码问题的filter-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--Restful前端控制器-->
<servlet>
<servlet-name>springMVC_rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>l</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springMVC_rest</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Listener的初始化过程
⾸先定义了<context-param>标签,⽤于配置⼀个全局变量,<context-param>标签的内容读取后会被放进application中,做为Web应⽤的全局变量使⽤,接下来创建listener时会使⽤到这个全局变量,因此,Web应⽤在容器中部署后,进⾏初始化时会先读取这个全局变量,之后再进⾏上述讲解的初始化启动过程。
接着定义了⼀个ContextLoaderListener类的listener。查看ContextLoaderListener的类声明源码如下图:
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
}
ContextLoaderListener类继承了ContextLoader类并实现了ServletContextListener接⼝,⾸先看⼀下前⾯讲述的ServletContextListener接⼝源码:
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* glassfish.dev.java/public/CDDL+GPL_1_1.html
* or packager/ See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* /licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and
* limitations under the License.
*/
package javax.servlet;
import java.util.EventListener;
/**
* Interface for receiving notification events about ServletContext
* lifecycle changes.
* lifecycle changes.
*
* <p>In order to receive these notification events, the implementation
* class must be either declared in the deployment descriptor of the web
* application, annotated with {@link javax.servlet.annotation.WebListener},
* or registered via one of the addListener methods defined on
* {@link ServletContext}.
*
* <p>Implementations of this interface are invoked at their
* {@link #contextInitialized} method in the order in which they have been
* declared, and at their {@link #contextDestroyed} method in reverse
* order.
*
* @see ServletContextEvent
*
* @since Servlet 2.3
*/
public interface ServletContextListener extends EventListener {
/**
* Receives notification that the web application initialization
* process is starting.
*
* <p>All ServletContextListeners are notified of context
* initialization before any filters or servlets in the web
* application are initialized.
*
* @param sce the ServletContextEvent containing the ServletContext
* that is being initialized
*/
public void contextInitialized(ServletContextEvent sce);
/**
* Receives notification that the ServletContext is about to be
* shut down.
*
* <p>All servlets and filters will have been destroyed before any
* ServletContextListeners are notified of context
* destruction.
*
* @param sce the ServletContextEvent containing the ServletContext
* that is being destroyed
*/
public void contextDestroyed(ServletContextEvent sce);
}
springmvc常用标签该接⼝只有两个⽅法contextInitialized和contextDestroyed,这⾥采⽤的是观察者模式,也称为订阅-发布模式,实现了该接⼝的listener会向发布者进⾏订阅,当Web应⽤初始化或销毁时会分别调⽤上述两个⽅法。
继续看ContextLoaderListener,该listener实现了ServletContextListener接⼝,因此在Web应⽤初始化时会调⽤该⽅法,该⽅法的具体实现如下:
/
**
* Initialize the root web application context.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
ServletContext());
}
ContextLoaderListener的contextInitialized()⽅法直接调⽤了initWebApplicationContext()⽅法,这个⽅法是继承⾃ContextLoader类,通过函数名可以知道,该⽅法是⽤于初始化Web应⽤上下⽂,即IoC容器,这⾥使⽤的是代理模式,继续查看ContextLoader
类的initWebApplicationContext()⽅法的源码如下:
/**
* Initialize Spring's web application context for the given servlet context,
* using the application context provided at construction time, or creating a new one
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
* @param servletContext current servlet context
* @return the new WebApplicationContext
* @see #ContextLoader(WebApplicationContext)
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
*/
//servletContext,servlet上下⽂,即application对象
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
/*
⾸先通过WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
这个String类型的静态变量获取⼀个根IoC容器,根IoC容器作为全局变量
存储在application对象中,如果存在则有且只能有⼀个
如果在初始化根WebApplicationContext即根IoC容器时发现已经存在
则直接抛出异常,因此l中只允许存在⼀个ContextLoader类或其⼦类的对象
*/
if (Attribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in l!");
}
Log logger = Log(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
/
/ it is available on ServletContext shutdown.
// 如果当前成员变量中不存在WebApplicationContext则创建⼀个根WebApplicationContext
if (t == null) {
}
if (t instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) t;
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 (Parent() == null) {
/
/ The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
//为根WebApplicationContext设置⼀个⽗容器
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
//配置并刷新整个根IoC容器,在这⾥会进⾏Bean的创建和初始化
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
/*
将创建好的IoC容器放⼊到application对象中,并设置key为WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
因此,在SpringMVC开发中可以在jsp中通过该key在application对象中获取到根IoC容器,进⽽获取到相应的Ben
*/
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论