读Spring源代码之按图索骥(一)Context创建与配置文件加载
来源:互联网 发布:淘宝淘你喜欢 编辑:程序博客网 时间:2024/06/10 03:39
点击打开链接
Spring 和 Struts在web.xml中增加的配置:
<!-- spring的配置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/SpringContext/applicationContext-web.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> <init-param> <param-name>config</param-name> <param-value>struts-default.xml,struts-plugin.xml,struts/struts.xml</param-value> </init-param> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping
第一个tag定义的是spring的配置文件地址到环境参数(context parameter)
第二个tag定义一个listener为org.springframework.web.context.ContextLoaderListener,这里相当于j2ee容器给我们提供的main函数的切入点,可以让我们做一些系统初始化的工作,需要实现的类是:javax.servlet.ServletContextListener
第三个tag则定义了struts2的一个filter。Filter则是对每次请求(可以通过filter-mapping指定)做过滤处理,请求首先请过filter链的处理,然后再到HttpServlet的init方法。对应的类是:javax.servlet.Filter。上面先配置了一个filter,对应的类是org.apache.struts2.dispatcher.FilterDispatcher,参数则是struts的配置文件位置
第四个参数定义了filter怎样行为,显然它对.do为后缀的请求应用struts2这个名称的filter
这里需要首先搞清楚servlet规范中什么是listener? 详细请参见 Servlet Listener和Filter
查看ContextLoaderListener可知,它正好继承了javax.servlet.ServletContextListener,用于监听javax.servlet.ServletContextEvent事件查看ContextLoaderListener可知,它正好继承了javax.servlet.ServletContextListener,用于监听javax.servlet.ServletContextEvent事件
/* * Copyright 2002-2007 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 * * http://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 Spring's root {@link WebApplicationContext}. * Simply delegates to {@link ContextLoader}. * * <p>This listener should be registered after * {@link org.springframework.web.util.Log4jConfigListener} * in <code>web.xml</code>, if the latter is used. * * @author Juergen Hoeller * @since 17.02.2003 * @see ContextLoaderServlet * @see org.springframework.web.util.Log4jConfigListener */public class ContextLoaderListener implements ServletContextListener { private ContextLoader contextLoader; /** * Initialize the root web application context. */ public void contextInitialized(ServletContextEvent event) { this.contextLoader = createContextLoader(); this.contextLoader.initWebApplicationContext(event.getServletContext()); } /** * Create the ContextLoader to use. Can be overridden in subclasses. * @return the new ContextLoader */ protected ContextLoader createContextLoader() { return new ContextLoader(); } /** * Return the ContextLoader used by this listener. * @return the current ContextLoader */ public ContextLoader getContextLoader() { return this.contextLoader; } /** * Close the root web application context. */ public void contextDestroyed(ServletContextEvent event) { if (this.contextLoader != null) { this.contextLoader.closeWebApplicationContext(event.getServletContext()); } } }
此类implement了ServletContextListener的两个方法:
public void contextInitialized(ServletContextEvent event);public void contextDestroyed(ServletContextEvent event);
分别做context的初始化和销毁
另外提供了一个protected方法:protected ContextLoader createContextLoader() 用于创建真正做事情的代理类CotextLoader
和一个public方法:public ContextLoader getContextLoader();
可见,这个Listener类直接将工作代理给了ContextLoader类了
我们按图索骥,下面再分析org.springframework.web.context.ContextLoader
ContextLoader里面有个私有成员:private WebApplicationContext context
此变量提供了create方法:
createWebApplicationContext(ServletContext servletContext, ApplicationContext parent)
因为Spring提供了多种WebApplicationContext类,所以需要一个方法来决定使用哪个WebApplicationContextContext类
protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException { String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); if (contextClassName != null) { try { return ClassUtils.forName(contextClassName); } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load custom context class [" + contextClassName + "]", ex); } } else { contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); try { return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); } catch (ClassNotFoundException ex) { throw new ApplicationContextException( "Failed to load default context class [" + contextClassName + "]", ex); } } }
public static final String CONTEXT_CLASS_PARAM = "contextClass";
所以如果在web.xml中的<context-param> </context-param>中定义了参数contextClass,那么直接就决定了用此Context类
否则,就应用缺省策略来决定使用哪个Context类。
缺省策略如下:
private static final Properties defaultStrategies; 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, ContextLoader.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage()); }}
实际上,缺省策略从org\springframework\web\context\ContextLoader.properties 文件中取得属性org.springframework.web.context.WebApplicationContext
我们看看ContextLoader.properties文件的内容:
# Default WebApplicationContext implementation class for ContextLoader.# Used as fallback when no explicit context implementation has been specified as context-param.# Not meant to be customized by application developers. org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
显然,缺省的Context类就是 XmlWebApplicationContext类
!!!真累啊,Spring...
OK,总算知道用哪个Context类了,那么现在到了create这个Context实例的时候了
protected WebApplicationContext createWebApplicationContext( ServletContext servletContext, ApplicationContext parent) throws BeansException { Class contextClass = determineContextClass(servletContext); if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); } ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setParent(parent); wac.setServletContext(servletContext); wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM)); customizeContext(servletContext, wac); wac.refresh(); return wac; }
这里很容易理解,只不过它的创建不是直接new,而是封装了一层,调用BeanUtils.instantiateClass()工具方法
接下来设定WebApplicationCcontext实例的parent, servletContext,
其中配置文件位置(web.xml中)的contextConfigLocation参数指定的
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/SpringContext/applicationContext-web.xml </param-value></context-param>
倒数第二行调用的customizeContext()方法目前Spring实现代码是空的,估计留作以后(看来万事要留余地啊^_^)
最后一件事就是调用WebApplicationContext的refresh()方法。(这个方法是个stratup方法,很重要。他干的事情后面会着重涉及)
最后就是真正做事的initWebApplicationContext()方法:
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) throws IllegalStateException, BeansException { if (servletContext.getAttribute(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 your web.xml!"); } servletContext.log("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime = System.currentTimeMillis(); try { // Determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. this.context = createWebApplicationContext(servletContext, parent); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context); if (logger.isDebugEnabled()) { logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); } if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); } return this.context; } catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } catch (Error err) { logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; } }
它其实做得事情很简单,调用loadParentContext()方法获取父context,调用createWebApplicationContext()创建WebApplicationContext实例
一切都似乎完成了,至少我们明白了配置文件是如何加载进去的,至于IoC容器如何帮你注入配置文件中的bean,下次再探索。线索是什么呢?你还记得在createWebApplication()的最后一步做什么了吗?refresh(), 对了,这个就是你作为职业"嘿客"要探索的下一个线索
- 读Spring源代码之按图索骥(一)Context创建与配置文件加载
- Spring配置文件之标签(一)<context:component-scan>
- Struts2源代码分析(一)配置文件加载
- Struts2源代码分析(一)配置文件加载
- Struts2源代码分析(一)配置文件加载 .
- Struts2源代码分析(一)配置文件加载
- Struts2源代码分析(一)配置文件加载
- spring源代码之bean的加载(一)
- Spring配置文件详解一:<:<context:annotation-config/>与<context:component-scan base-package="com.xx
- Spring配置文件详解一:<context:annotation-config/>与<context:component-scan base-package="com.xx
- Spring配置文件与 spring <context:annotation-config>
- spring和spring mvc配置文件context加载的区
- Spring与classpath*加载配置文件
- Spring之配置文件加载方式
- Spring之配置文件加载方式
- Spring之配置文件加载方式
- Spring之配置文件加载方式
- Spring之配置文件加载方式
- Android中对Log日志文件的分析
- powerDesigner 文章转载 集合
- df及du查看文件系统及文件夹使用大小
- JAVA基础 之 集合概述
- 程序异常时,关闭Visual Studio 2008 实时调试器
- 读Spring源代码之按图索骥(一)Context创建与配置文件加载
- 2110,7110,8210 IC卡驱动总结
- Java读取Excel内容&jsp页面内容导出到Excel中
- Android 应用程序窗体显示状态操作(requestWindowFeature()的应用)
- 读写注册表
- 浅论中国当下情景喜剧发展
- c/c++ scanf printf 用法与优化
- Spring MVC学习之五:注解用法总结
- Automake 使用