spring的ioc带来的最大的好处是解耦合,但是spring本身就是一个耦合度很高的框架
现在在多数企业中spring框架应用比较广泛,但是网上对spring框架解析比较详细的比较少,所以今天就让我们来看看spring框架在web中如何运行
<!-- 创建Spring的监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
在web.xml中配置spring的监听器,其实如何看一个javaee项目所使用那些框架在web.xml中差不多可以一目了然,contextConfigLocation是放spring的配置文件的地方,名字一定要叫contextConfigLocation,在value中可以配置多个applicationContext.xml,如果没有配置contextConfigLocation则 去加载/WEB-INF/下的applicationContext.xml。
但是,如果没有指定的话,默认会去/WEB-INF/下加载applicationContext.xml。这里不多说,有兴趣的同学可以自己上网搜
创建Listener 类必须实现ServletContextListener 接口,该接口包含两个方法。
• contextInitialized(ServletContextEvent sce): 启动Web 应用时,系统调用该Filter的方法。
• contextDestroyed(ServletContextEvent sce): 关闭Web 应用时候,系统调用Filter的方法。
Listener 用于启动Web 应用的后台服务程序,但不负责处理及响应用户请求,因此无须配置URL。若将Listener 配置在Web 容器中(如果Web 容器支持Listener),则Listener 将随Web 应用的启动而启动。
看下ContextLoaderListener
public void contextInitialized(ServletContextEvent event)
/* */ {
/* 44 */ this.contextLoader = createContextLoader();
/* 45 */ this.contextLoader.initWebApplicationContext(event.getServletContext());
/* */ }
/* */
/* */ protected ContextLoader createContextLoader()
/* */ {
/* 53 */ return new ContextLoader();
/* */ }
这个很简单createContextLoader()中实例化ContextLoader关键是initWebApplicationContext(event.getServletContext());
那我们去看下ContextLoader类
public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
/* */ throws IllegalStateException, BeansException
/* */ {
/* 181 */ if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
/* 182 */ 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!");
/* */ }
/* */
/* 187 */ servletContext.log("Initializing Spring root WebApplicationContext");
/* 188 */ if (logger.isInfoEnabled()) {
/* 189 */ logger.info("Root WebApplicationContext: initialization started");
/* */ }
/* 191 */ long startTime = System.currentTimeMillis();
/* */ try
/* */ {
/* 195 */ ApplicationContext parent = loadParentContext(servletContext);
/* */
/* 199 */ this.context = createWebApplicationContext(servletContext, parent);
/* 200 */ servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
/* 201 */ currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context);
/* */
/* 203 */ if (logger.isDebugEnabled()) {
/* 204 */ logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
/* */ }
/* */
/* 207 */ if (logger.isInfoEnabled()) {
/* 208 */ long elapsedTime = System.currentTimeMillis() - startTime;
/* 209 */ logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
/* */ }
/* */
/* 212 */ return this.context;
/* */ }
/* */ catch (RuntimeException ex) {
/* 215 */ logger.error("Context initialization failed", ex);
/* 216 */ servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
/* 217 */ throw ex;
/* */ }
/* */ catch (Error err) {
/* 220 */ logger.error("Context initialization failed", err);
/* 221 */ servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
/* 222 */ }throw err;
/* */ }
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null)
这个可以看下下面抛出的异常,说是的WebApplicationContext已经被初始化了,检查是否你已经在web.xml中配置了。意思很明白,如果你实例两个ContextLoader就会抛出这个异常,至于为什么后面会讲下
在看下面
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
这个一般是写日志,不用看
再看下面
ApplicationContext parent = loadParentContext(servletContext);
我们去到ContextLoader中loadParentContext中
</pre><pre class="html" name="code">protected ApplicationContext loadParentContext(ServletContext servletContext)
/* */ throws BeansException
/* */ {
/* 330 */ ApplicationContext parentContext = null;
/* 331 */ String locatorFactorySelector = servletContext.getInitParameter("locatorFactorySelector");
/* 332 */ String parentContextKey = servletContext.getInitParameter("parentContextKey");
/* */
/* 334 */ if (parentContextKey != null)
/* */ {
/* 336 */ BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);
/* 337 */ if (logger.isDebugEnabled()) {
/* 338 */ logger.debug("Getting parent context definition: using parent context key of '" + parentContextKey + "' with BeanFactoryLocator");
/* */ }
/* *
/* 341 */ this.parentContextRef = locator.useBeanFactory(parentContextKey);
/* 342 */ parentContext = (ApplicationContext)this.parentContextRef.getFactory();
/* */ }
/* */
/* 345 */ return parentContext;
/* */ }
/* */