Spring 源码粘贴9 MVC

来源:互联网 发布:甲骨文和java的关系 编辑:程序博客网 时间:2024/06/05 00:46

入口DispatcherServlet

启动类ContextLoaderListener

当Web容器启动时,触发监听

public void contextInitialized(ServletContextEvent event) {initWebApplicationContext(event.getServletContext());}
这个方法在基类中实现,建立IoC容器和生成WebApplicationContext

public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
先看这个WebApplicationContext接口

public interface WebApplicationContext extends ApplicationContext {/** * Context attribute to bind root WebApplicationContext to on successful startup. * <p>Note: If the startup of the root context fails, this attribute can contain * an exception or error as value. Use WebApplicationContextUtils for convenient * lookup of the root WebApplicationContext. * @see org.springframework.web.context.support.WebApplicationContextUtils#getWebApplicationContext * @see org.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContext */String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";/** * Scope identifier for request scope: "request". * Supported in addition to the standard scopes "singleton" and "prototype". */String SCOPE_REQUEST = "request";/** * Scope identifier for session scope: "session". * Supported in addition to the standard scopes "singleton" and "prototype". */String SCOPE_SESSION = "session";/** * Scope identifier for global session scope: "globalSession". * Supported in addition to the standard scopes "singleton" and "prototype". */String SCOPE_GLOBAL_SESSION = "globalSession";/** * Scope identifier for the global web application scope: "application". * Supported in addition to the standard scopes "singleton" and "prototype". */String SCOPE_APPLICATION = "application";/** * Name of the ServletContext environment bean in the factory. * @see javax.servlet.ServletContext */String SERVLET_CONTEXT_BEAN_NAME = "servletContext";/** * Name of the ServletContext/PortletContext init-params environment bean in the factory. * <p>Note: Possibly merged with ServletConfig/PortletConfig parameters. * ServletConfig parameters override ServletContext parameters of the same name. * @see javax.servlet.ServletContext#getInitParameterNames() * @see javax.servlet.ServletContext#getInitParameter(String) * @see javax.servlet.ServletConfig#getInitParameterNames() * @see javax.servlet.ServletConfig#getInitParameter(String) */String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";/** * Name of the ServletContext/PortletContext attributes environment bean in the factory. * @see javax.servlet.ServletContext#getAttributeNames() * @see javax.servlet.ServletContext#getAttribute(String) */String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";/** * Return the standard Servlet API ServletContext for this application. * <p>Also available for a Portlet application, in addition to the PortletContext. */ServletContext getServletContext();}
这个接口就将servlet上下文引入了

在上面的创建WebApplicationContext时的代码

this.context = createWebApplicationContext(servletContext);
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {Class<?> contextClass = determineContextClass(sc);...}
/** * Return the WebApplicationContext implementation class to use, either the * default XmlWebApplicationContext or a custom context class if specified. */protected Class<?> determineContextClass(ServletContext servletContext) {...}
默认情况下都是使用XmlWebApplicationContext,所以看下这个实现类吧.
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {/** Default config location for the root context */public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";/** Default prefix for building a config location for a namespace */public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";/** Default suffix for building a config location for a namespace */public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";/** * Loads the bean definitions via an XmlBeanDefinitionReader. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see #initBeanDefinitionReader * @see #loadBeanDefinitions */@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.initBeanDefinitionReader(beanDefinitionReader);loadBeanDefinitions(beanDefinitionReader);}/** * Initialize the bean definition reader used for loading the bean * definitions of this context. Default implementation is empty. * <p>Can be overridden in subclasses, e.g. for turning off XML validation * or using a different XmlBeanDefinitionParser implementation. * @param beanDefinitionReader the bean definition reader used by this context * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setValidationMode * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader#setDocumentReaderClass */protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {}/** * Load the bean definitions with the given XmlBeanDefinitionReader. * <p>The lifecycle of the bean factory is handled by the refreshBeanFactory method; * therefore this method is just supposed to load and/or register bean definitions. * <p>Delegates to a ResourcePatternResolver for resolving location patterns * into Resource instances. * @throws IOException if the required XML document isn't found * @see #refreshBeanFactory * @see #getConfigLocations * @see #getResources * @see #getResourcePatternResolver */protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {String[] configLocations = getConfigLocations();if (configLocations != null) {for (String configLocation : configLocations) {reader.loadBeanDefinitions(configLocation);}}}/** * The default location for the root context is "/WEB-INF/applicationContext.xml", * and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet" * (like for a DispatcherServlet instance with the servlet-name "test"). */@Overrideprotected String[] getDefaultConfigLocations() {if (getNamespace() != null) {return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};}else {return new String[] {DEFAULT_CONFIG_LOCATION};}}}
这里配置了一些web上才用得到的属性,比如默认的xml名字和目录等.除了获取xml信息外,其他的IoC容器功能都在基类中实现了


开始之前的initWebApplicationContext()

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {...if (this.context == null) {this.context = createWebApplicationContext(servletContext);}if (this.context instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;if (!cwac.isActive()) {//设置根上下文的双亲上下文if (cwac.getParent() == null) {ApplicationContext parent = loadParentContext(servletContext);cwac.setParent(parent);}configureAndRefreshWebApplicationContext(cwac, servletContext);}}servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);ClassLoader ccl = Thread.currentThread().getContextClassLoader();if (ccl == ContextLoader.class.getClassLoader()) {currentContext = this.context;}else if (ccl != null) {currentContextPerThread.put(ccl, this.context);}return this.context;...}
获取ServletContext然后读取一些信息,创建初始化WebApplicationContext,并将其作为根上下文,并绑定在ServletContext上.可以通过WebApplicationContextUtils.getWebApplicationContext()来获取
创建根上下文方法

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {Class<?> contextClass = determineContextClass(sc);if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Custom context class [" + contextClass.getName() +"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");}return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);}
这方法和以前不一样了.这里并没有设置什么属性,也没有调用refresh()只是简简单单的实例化了这个对象,然而这些动作都在外面一层的下一句.优雅~~~

configureAndRefreshWebApplicationContext(cwac, servletContext);
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {if (ObjectUtils.identityToString(wac).equals(wac.getId())) {String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);if (idParam != null) {wac.setId(idParam);}else {wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +ObjectUtils.getDisplayString(sc.getContextPath()));}}wac.setServletContext(sc);String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);if (configLocationParam != null) {wac.setConfigLocation(configLocationParam);}ConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment) env).initPropertySources(sc, null);}customizeContext(sc, wac);wac.refresh();}