web.xml中启用Spring
在一般的web应用程序,我们倘若用到Spring的话,需要在web.xml中配置以下的信息来使一些容器,例如Tomcat、Jetty等来加载Spring
<!-- Spring配置文件信息 -->
<context-param>
<!-- 这个contextConfigLocation参数是用来加载spring相关配置的标签 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:com/conf/applicationContext.xml</param-value>
</context-param>
<!-- ContextLoaderListener监听器 -->
<!-- ContextLoaderListener的作用就是启动Web容器时,自动装配
ApplicationContext.xml的配置信息
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Spring主要通过ContextLoaderListener类在应用启动时加载其服务
ContextLoaderListener的官方注释
查看某个类的重要功能最好是观察其的注释,ContextLoaderLinstener官方注释如下:
//父级启动类,可用ContextLoader启动和ContextCleanupListener来关闭Spring的根web应用上下文
Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.
Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
//这里给出了提示,如果需要用到自定义log4j的配置的话,则ContextListener需要在Log4jConfigListener之后
<p>This listener should be registered after {@link org.springframework.web.util.Log4jConfigListener}
in {@code web.xml}, if the latter is used.
//从Spring3.1之后,注入根web应用上下文可通过 WebApplicationInitializer,容器在启动会加载此接口,但是有个要求是容器的Servlet版本必须是3.0+,对Tomcat来说必须是7.0.15版本以上
<p>As of Spring 3.1, {@code ContextLoaderListener} supports injecting the root web
application context via the {@link #ContextLoaderListener(WebApplicationContext)}
constructor, allowing for programmatic configuration in Servlet 3.0+ environments.
See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
@author Juergen Hoeller
@author Chris Beams
@since 17.02.2003
@see #setContextInitializers
@see org.springframework.web.WebApplicationInitializer
@see org.springframework.web.util.Log4jConfigListener
重要的批注都在新增的注释上,并且我们可以发现,web.xml中的listener节点具有代码逻辑上的先写先加载的特点。
特别需要注意的是如果用户需要用到
Log4jConfigListener的话,则必须写在ContextLoaderListener的前面
ContextLoaderListener结构
public class ContextLoaderListener extends ContextLoader implements ServletContextListener{}
下面是ContextLoaderListener的源代码:
/*
* Copyright 2002-2018 the original author or authors.
*
* 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
*
* https://www.apache.org/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 org.springframework.web.context;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.
* Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
*
* <p>As of Spring 3.1, {@code ContextLoaderListener} supports injecting the root web
* application context via the {@link #ContextLoaderListener(WebApplicationContext)}
* constructor, allowing for programmatic configuration in Servlet 3.0+ environments.
* See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
*
* @author Juergen Hoeller
* @author Chris Beams
* @since 17.02.2003
* @see #setContextInitializers
* @see org.springframework.web.WebApplicationInitializer
*/
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
/**
* Create a new {@code ContextLoaderListener} that will create a web application
* context based on the "contextClass" and "contextConfigLocation" servlet
* context-params. See {@link ContextLoader} superclass documentation for details on
* default values for each.
* <p>This constructor is typically used when declaring {@code ContextLoaderListener}
* as a {@code <listener>} within {@code web.xml}, where a no-arg constructor is
* required.
* <p>The created application context will be registered into the ServletContext under
* the attribute name {@link WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE}
* and the Spring application context will be closed when the {@link #contextDestroyed}
* lifecycle method is invoked on this listener.
* @see ContextLoader
* @see #ContextLoaderListener(WebApplicationContext)
* @see #contextInitialized(ServletContextEvent)
* @see #contextDestroyed(ServletContextEvent)
*/
public ContextLoaderListener() {
}
/**
* Create a new {@code ContextLoaderListener} with the given application context. This
* constructor is useful in Servlet 3.0+ environments where instance-based
* registration of listeners is possible through the {@link javax.servlet.ServletContext#addListener}
* API.
* <p>The context may or may not yet be {@linkplain
* org.springframework.context.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 has not already been assigned an {@linkplain
* org.springframework.context.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 #customizeContext} will be called</li>
* <li>Any {@link org.springframework.context.ApplicationContextInitializer ApplicationContextInitializer org.springframework.context.ApplicationContextInitializer ApplicationContextInitializers}
* specified through the "contextInitializerClasses" init-param will be applied.</li>
* <li>{@link org.springframework.context.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.
* <p>In any case, the given application context will be registered into the
* ServletContext under the attribute name {@link
* WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE} and the Spring
* application context will be closed when the {@link #contextDestroyed} lifecycle
* method is invoked on this listener.
* @param context the application context to manage
* @see #contextInitialized(ServletContextEvent)
* @see #contextDestroyed(ServletContextEvent)
*/
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
/**
* Initialize the root web application context.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
/**
* Close the root web application context.
*/
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
最应该关注的是ServletContextListenr接口,我们应该知道实现此接口的类会在应用启动的时候,自动的调用其接口方法contextInitialized(ServletContextEvent event);
在关闭应用时候则会调用其另外一个接口方法contextDestroyed(ServletContextEvent evet)用来关闭web上下文信息。
- 初始化
public void contextInitialized(ServletContextEvent event) { //调用的是父类ContextLoader的方法,看出来这是启动的关键 initWebApplicationContext(event.getServletContext()); } - 关闭
//与初始化相对 closeWebApplicationContext(event.getServletContext()); //使用ContextCleanupLister监听类来销毁ServletContext的springwork属性信息 ContextCleanupListener.cleanupAttributes(event.getServletContext());
这里我们简单的看下销毁属性的代码方法
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
/**
* Find all Spring-internal ServletContext attributes which implement
* {@link DisposableBean} and invoke the destroy method on them.
* @param servletContext the ServletContext to check
* @see DisposableBean#destroy()
*/
static void cleanupAttributes(ServletContext servletContext) {
Enumeration<String> attrNames = servletContext.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = attrNames.nextElement();
//筛选出专属spring的属性
if (attrName.startsWith("org.springframework.")) {
Object attrValue = servletContext.getAttribute(attrName);
//基本WebApplication都实现了DisposableBean接口,表明所有的Bean都是可以释放的
if (attrValue instanceof DisposableBean) {
try {
((DisposableBean) attrValue).destroy();
}
catch (Throwable ex) {
if (logger.isWarnEnabled()) {
logger.warn("Invocation of destroy method failed on ServletContext " +
"attribute with name '" + attrName + "'", ex);
}
}
}
}
}
}
记录总结
web.xml中的listener节点具有先写先加载的特点,类似于java代码中的顺序执行
Log4jConfigListener类加载必须在ContextLoaderListenr类之前
ContextLoaderListener启动Spring并生成Spring根web服务上下文则是通过其父类ContextLoader来实现的,其销毁也只会销毁具有
org.springwork前缀的属性ServletContext代表应用服务上下文,其可以读取
<context-param>级别的参数,而ServletConfig/FilterConfig则会读取其相应servlet节点/filter节点下的<init-param>参数web.xml中listener、servlet、filter执行顺序为listener>filter>servlet,同类型的执行顺序为listener满足先写先加载,servlet、filter则由
mapping节点的先后顺序加载
本文介绍了Spring在web应用程序中的启用,特别是在web.xml中配置ContextLoaderListener的角色。ContextLoaderListener的官方注释强调了配置顺序的重要性,该监听器在应用启动时加载Spring服务。此外,文章还探讨了ContextLoaderListener的结构,包括初始化和关闭web上下文的方法。最后,总结了web.xml中listener、servlet、filter的加载顺序,并指出Log4jConfigListener应先于ContextLoaderListener加载。


被折叠的 条评论
为什么被折叠?



