`
gstarwd
  • 浏览: 1491143 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

读Spring源代码之按图索骥(一)Context创建与配置文件加载

阅读更多

Spring 和 Struts在web.xml中增加的配置:

   1:
 <!-- spring的配置 -->
   2:
 <
context-param
>
   3:
     <
param-name
>
contextConfigLocation</
param-name
>
   4:
     <
param-value
>
classpath:/SpringContext/applicationContext-web.xml</
param-value
>
   5:
 </
context-param
>
    
   7:
  
   8:
 <
listener
>
   9:
     <
listener-class
>
org.springframework.web.context.ContextLoaderListener
  10:
     </
listener-class
>
  11:
 </
listener
>
  12:
  
  13:
 <
filter
>
  14:
     <
filter-name
>
struts2</
filter-name
>
  15:
     <
filter-class
>
org.apache.struts2.dispatcher.FilterDispatcher</
filter-class
>
  17:
     <
init-param
>
  18:
         <
param-name
>
config</
param-name
>
  19:
         <
param-value
>
struts-default.xml,struts-plugin.xml,struts/struts.xml</
param-value
>
  20:
     </
init-param
>
  21:
 </
filter
>
  22:
  
  23:
 <
filter-mapping
>
  24:
     <
filter-name
>
struts2</
filter-name
>
  25:
     <
url-pattern
>
*.do</
url-pattern
>
  26:
 </
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事件

/*
 * 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源代码解析

    Spring源代码解析(一):IOC容器 Spring源代码解析(二):IoC容器在Web容器中的启动 Spring源代码解析(三):Spring JDBC Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy Spring源...

    spring-context 源代码

    spring-context 源代码spring-context 源代码spring-context 源代码spring-context 源代码

    Spring 源代码解析

    Spring 源代码解析Spring 源代码解析Spring 源代码解析Spring 源代码解析Spring 源代码解析Spring 源代码解析Spring 源代码解析Spring 源代码解析Spring 源代码解析Spring 源代码解析Spring 源代码解析Spring 源代码...

    JavaEE源代码 spring-context

    JavaEE源代码 spring-contextJavaEE源代码 spring-contextJavaEE源代码 spring-contextJavaEE源代码 spring-contextJavaEE源代码 spring-contextJavaEE源代码 spring-contextJavaEE源代码 spring-contextJavaEE源...

    Spring源代码解析.rar

    Spring源代码解析1:IOC容器.doc Spring源代码解析2:IoC容器在Web容器中的启动.doc Spring源代码解析3:Spring JDBC .doc Spring源代码解析4:Spring MVC .doc Spring源代码解析5:Spring AOP获取Proxy .doc Spring...

    Spring源代码解析(一):IOC容器.doc

    Spring源代码解析(一):IOC容器.doc

    JavaEE源代码 spring-toplink

    JavaEE源代码 spring-toplinkJavaEE源代码 spring-toplinkJavaEE源代码 spring-toplinkJavaEE源代码 spring-toplinkJavaEE源代码 spring-toplinkJavaEE源代码 spring-toplinkJavaEE源代码 spring-toplinkJavaEE源...

    Spring动态加载配置文件

    本文档是很专业的 Spring动态加载配置文件,实现热部署方案。

    精通spring源代码精通spring源代码

    精通spring源代码精通spring源代码精通spring源代码精通spring源代码精通spring源代码精通spring源代码

    JavaEE源代码 spring-core

    JavaEE源代码 spring-coreJavaEE源代码 spring-coreJavaEE源代码 spring-coreJavaEE源代码 spring-coreJavaEE源代码 spring-coreJavaEE源代码 spring-coreJavaEE源代码 spring-coreJavaEE源代码 spring-coreJavaEE源...

    spring源代码

    spring源代码

    spring完整源代码

    绝对完整,例如: spring-aop spring-adpects ...spring-context spring-context-support spring-core spring-expression spring-framework-bom spring-instrument spring-instrument-tomcat spring-jdbc 等等

    JavaEE源代码 spring-jdo

    JavaEE源代码 spring-jdoJavaEE源代码 spring-jdoJavaEE源代码 spring-jdoJavaEE源代码 spring-jdoJavaEE源代码 spring-jdoJavaEE源代码 spring-jdoJavaEE源代码 spring-jdoJavaEE源代码 spring-jdoJavaEE源代码 ...

    JavaEE源代码 spring-jpa

    JavaEE源代码 spring-jpaJavaEE源代码 spring-jpaJavaEE源代码 spring-jpaJavaEE源代码 spring-jpaJavaEE源代码 spring-jpaJavaEE源代码 spring-jpaJavaEE源代码 spring-jpaJavaEE源代码 spring-jpaJavaEE源代码 ...

    JavaEE源代码 spring-dao

    JavaEE源代码 spring-daoJavaEE源代码 spring-daoJavaEE源代码 spring-daoJavaEE源代码 spring-daoJavaEE源代码 spring-daoJavaEE源代码 spring-daoJavaEE源代码 spring-daoJavaEE源代码 spring-daoJavaEE源代码 ...

    JavaEE源代码 spring-mock

    JavaEE源代码 spring-mockJavaEE源代码 spring-mockJavaEE源代码 spring-mockJavaEE源代码 spring-mockJavaEE源代码 spring-mockJavaEE源代码 spring-mockJavaEE源代码 spring-mockJavaEE源代码 spring-mockJavaEE源...

    JavaEE源代码 spring-jdbc

    JavaEE源代码 spring-jdbcJavaEE源代码 spring-jdbcJavaEE源代码 spring-jdbcJavaEE源代码 spring-jdbcJavaEE源代码 spring-jdbcJavaEE源代码 spring-jdbcJavaEE源代码 spring-jdbcJavaEE源代码 spring-jdbcJavaEE源...

    JavaEE源代码 spring-beans

    JavaEE源代码 spring-beansJavaEE源代码 spring-beansJavaEE源代码 spring-beansJavaEE源代码 spring-beansJavaEE源代码 spring-beansJavaEE源代码 spring-beansJavaEE源代码 spring-beansJavaEE源代码 spring-...

Global site tag (gtag.js) - Google Analytics