1: web.xml配置
<!-- 加载spring容器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- web容器加载了所有 applicationContext相关的配置文件 -->
<param-value>classpath*:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
2: 加载完后
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
//servlet容器加载完之后, 执行这个方法 : 初始化web容器
public void contextInitialized(ServletContextEvent event) {
this.initWebApplicationContext(event.getServletContext());
}
public void contextDestroyed(ServletContextEvent event) {
this.closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
3: 跳入这个方法 : (删除无用的代码) :initWebApplicationContext(ServletContext servletContext)
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
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 ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
//這個方法是主要是完成 spring容器的ioc,di,aop的操作
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
return this.context;
}
catch (RuntimeException ex) {
throw err;
}
}
4: 继续进入这个方法: configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc)
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
wac.setServletContext(sc);
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
// 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(sc, null);
}
//个性化上下文: spring的WebApplicationContext和ServletContext
customizeContext(sc, wac);
//这个方法大家应该比较熟悉了.
wac.refresh();
}
5: 再看 wac.refresh()
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//准备上下文 : 等待被刷新
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
6: 加载servlet流程: 初始化->请求->销毁
HttpServlet :
init() -> doGet(), doPost() -> destroy();
启动阶段:contextInitialized->Filter.init->Servlet.init 这个方法保证了spring mvc的组件的初始化
(web.xml设置<load-on-startup>1</load-on-startup>) 访问阶段:RequestListener.requestInitialized->FirstFilter.doFilter->SecondFilter.doFilter->Servlet->返回SecondFilter.doFilter->返回FirstFilter.doFilter->RequestListener.requestDestroyed 简单:Listener->Filter->Servlet->Filter->Listener.
配置说明
listener:不配置url请求过滤 filter:需要配置url或servlet过滤 servlet:需要配置url或servlet过滤
按监听的对象划分
ServletContext对象监听器 HttpSession对象监听器 ServletRequest对象监听器
按监听的事件划分
对象自身的创建和销毁的监听器 对象中属性的创建和消除的监听器 session中的某个对象的状态变化的监听器
init()方法执行
首先是类:
[参考]
a) diapatcherServlet的初始化过程
[参考] []() springmvc的dispatch加载
DispatcherServlet实现了Servlet接口的实现类。Servlet的生命周期分为3个阶段:初始化、运行和销毁。而其初始化阶段可分为:
a) Servlet容器加载Servlet类,把类的.class文件中的数据读到内存中; b) Servlet容器中创建一个ServletConfig对象。该对象中包含了Servlet的初始化配置信息; c) Servlet容器创建一个Servlet对象; d) Servlet容器调用Servlet对象的init()方法进行初始化。 Servlet的初始化阶段会调用它的init()方法,DispatcherServlet也不例外,在它的父类HttpServletBean中找到了该方法。
servlet容器规范:
[参考]
Web应用 Servlet容器会实例化和调用Servlet,那Servlet是怎么注册到Servlet容器中的呢?一般来说,我们是以Web应用程序的方式来部署Servlet的,而根据Servlet规范,Web应用程序有一定的目录结构,在这个目录下分别放置了Servlet的类文件、配置文件以及静态资源,Servlet容器通过读取配置文件,就能找到并加载Servlet。
Web应用的目录结构大概是下面这样的:
| - MyWebApp | - WEB-INF/web.xml -- 配置文件,用来配置Servlet等 | - WEB-INF/lib/ -- 存放Web应用所需各种JAR包 | - WEB-INF/classes/ -- 存放你的应用类,比如Servlet类 | - META-INF/ -- 目录存放工程的一些信息
Servlet规范里定义了ServletContext这个接口来对应一个Web应用。
Web应用部署好后,Servlet容器在启动时会加载Web应用,并为每个Web应用创建唯一的ServletContext对象。你可以把ServletContext看成是一个全局对象,一个Web应用可能有多个Servlet,这些Servlet可以通过全局的ServletContext来共享数据,这些数据包括Web应用的初始化参数、Web应用目录下的文件资源等。由于ServletContext持有所有Servlet实例,你还可以通过它来实现Servlet请求的转发。
扩展机制 引入了Servlet规范后,你不需要关心Socket网络通信、不需要关心HTTP协议,也不需要关心你的业务类是如何被实例化和调用的,因为这些都被Servlet规范标准化了,你只要关心怎么实现的你的业务逻辑。这对于程序员来说是件好事,但也有不方便的一面。所谓规范就是说大家都要遵守,就会千篇一律,但是如果这个规范不能满足你的业务的个性化需求,就有问题了,因此设计一个规范或者一个中间件,要充分考虑到可扩展性。Servlet规范提供了两种扩展机制:Filter和Listener。
Filter是过滤器,这个接口允许你对请求和响应做一些统一的定制化处理,比如你可以根据请求的频率来限制访问,或者根据国家地区的不同来修改响应内容。过滤器的工作原理是这样的:Web应用部署完成后,Servlet容器需要实例化Filter并把Filter链接成一个FilterChain。当请求进来时,获取第一个Filter并调用doFilter方法,doFilter方法负责调用这个FilterChain中的下一个Filter。
Listener是监听器,这是另一种扩展机制。当Web应用在Servlet容器中运行时,Servlet容器内部会不断的发生各种事件,如Web应用的启动和停止、用户请求到达等。 Servlet容器提供了一些默认的监听器来监听这些事件,当事件发生时,Servlet容器会负责调用监听器的方法。当然,你可以定义自己的监听器去监听你感兴趣的事件,将监听器配置在web.xml中。比如Spring就实现了自己的监听器,来监听ServletContext的启动事件,目的是当Servlet容器启动时,创建并初始化全局的Spring容器。
servlet相关内容:
[参考]
//这个会执行 init方法
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
@Override
public final void init() throws ServletException {
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
throw ex;
}
}
// Let subclasses do whatever initialization they like.
initServletBean();
}
/**
* 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
*/
protected void initServletBean() throws ServletException {
}
}
然后转入类:
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {
this.webApplicationContext = (WebApplicationContext) applicationContext;
this.webApplicationContextInjected = true;
}
}
/**
* Overridden method of {@link HttpServletBean}, invoked after any bean properties
* have been set. Creates this servlet's WebApplicationContext.
*/
@Override
protected final void initServletBean() throws ServletException {
long startTime = System.currentTimeMillis();
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
throw ex;
}
}
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.
synchronized (this.onRefreshMonitor) {
//这个方法又是一个很重要的方法
//通过这个方法 调用到了 DispatcherServlet类的 onRefresh方法
//初始化 spring mvc 的九大组件
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
/**
* This method will be invoked after any bean properties have been set and
* the WebApplicationContext has been loaded. The default implementation is empty;
* subclasses may override this method to perform any initialization they require.
* @throws ServletException in case of an initialization exception
*/
protected void initFrameworkServlet() throws ServletException {
}
}
转到类: DispatcherServlet
public class DispatcherServlet extends FrameworkServlet {
/**
* This implementation calls {@link #initStrategies}.
*/
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
protected void initStrategies(ApplicationContext context) {
//初始化文件 组件
initMultipartResolver(context);
//初始化 Locale组件
initLocaleResolver(context);
//初始化主题 组件
initThemeResolver(context);
//初始化 url和method 的映射
initHandlerMappings(context);
//初始化 url和method的参数解析及视图
initHandlerAdapters(context);
//初始化异常 组件
initHandlerExceptionResolvers(context);
//初始化 请求转视图名称 组件
initRequestToViewNameTranslator(context);
//初始化 视图渲染组件
initViewResolvers(context);
//初始化 Flash 管理器组件
initFlashMapManager(context);
}
}
以上内容从其他地方引入图片做了参考