`

spring mvc 源码(一)web容器创建

阅读更多

spring mvc是一个mvc开源框架,由于与spring是父子关系,所以无缝兼容

 

spring mvc入口:

 

    <!-- spring MVC -->
    <servlet>
        <servlet-name>spring-mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:/spring-mvc-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

 spring mvc在web.xml中的配置如上,这是一个标准的servlet的配置,入口为:DispatcherServlet;

 

DispatcherServlet源码为:

 

public class DispatcherServlet extends FrameworkServlet {
//省略实现代码...
}

public abstract class FrameworkServlet extends HttpServletBean {
//省略实现代码...s
}

public abstract class HttpServletBean extends HttpServlet
		implements EnvironmentCapable, EnvironmentAware {
//省略实现代码
}

 由上面可知DispatcherServlet实现了HttpServlet接口,所以配置也使用servlet配置;

 

 

一个servlet的初始化时通过init()方法完成,那我们先从最顶层的类HttpServletBean看起,下面为HttpServletBean的init()方法的实现:

 

	@Override
	public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}

		// Set bean properties from init parameters.
		try {
			PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
			BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
			ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
			bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
			initBeanWrapper(bw);
			bw.setPropertyValues(pvs, true);
		}
		catch (BeansException ex) {
			logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
			throw ex;
		}

		// Let subclasses do whatever initialization they like.
                //留给子类进行扩展
		initServletBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Servlet '" + getServletName() + "' configured successfully");
		}
	}

 由上面的代码可知,方法前半部分做了一些初始化配置,initServletBean()被FrameworkServlet重写,下面是FrameworkServlet中initServletBean()的实现:

 

	@Override
	protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
		if (this.logger.isInfoEnabled()) {
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
                        //创建上下文,创建容器
			this.webApplicationContext = initWebApplicationContext();
			initFrameworkServlet();
		}
		catch (ServletException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}
		catch (RuntimeException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (this.logger.isInfoEnabled()) {
			long elapsedTime = System.currentTimeMillis() - startTime;
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
					elapsedTime + " ms");
		}
	}

        //被调用方法实现,创建spring mvc容器的实现
	protected WebApplicationContext initWebApplicationContext() {
                //获取父容器,即spring的容器
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		if (this.webApplicationContext != null) {
			// A context instance was injected at construction time -> use it
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent -> set
						// the root application context (if any; may be null) as the parent
                                                //设置父容器,父容器为spring的容器
						cwac.setParent(rootContext);
					}
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context. If one exists, it is assumed
			// that the parent context (if any) has already been set and that the
			// user has performed any initialization such as setting the context id
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// Either the context is not a ConfigurableApplicationContext with refresh
			// support or the context injected at construction time had already been
			// refreshed -> trigger initial onRefresh manually here.
			onRefresh(wac);
		}

		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
						"' as ServletContext attribute with name [" + attrName + "]");
			}
		}

		return wac;
	}

有上面代码可知:spring mvc上下文和spring 上下文的关系,spring mvc容器为子容器, spring的容器为父容器,所以spring mvc里在配置controller时,可以直接引用在spring中配置的service类;所以在web.xml配置中,要先配置spring的配置,然后配置spring mvc的配置,否则spring mvc的子容器无法使用父容器中的资源

 

在FrameworkServlet类中onRefresh()方法是一个空方法,并没有具体实现,而是被子类重写了,在子类DispatcherServlet中onRefresh()方法实现如下:

 

	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	/**
	 * Initialize the strategy objects that this servlet uses.
	 * <p>May be overridden in subclasses in order to initialize further strategy objects.
	 */
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

由上面的代码可知在DispatcherServlet中刷新容器的时候,做了大量的初始化工作,初始化了Resolver,HandlerMapping,Adapter

 

初始化Resolver:

 

	private void initLocaleResolver(ApplicationContext context) {
		try {
                        //先从上下文里查找  
			this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			// We need to use the default.
                        //上下文里没有则使用默认的
			this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
						"': using default [" + this.localeResolver + "]");
			}
		}
	}

 关于默认的resolver:在DispatcherServlet刚开始有一段静态初始化的代码:

 

 

	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, DispatcherServlet.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
		}
	}

 默认加载一个配置文件:与DispatcherServlet在同一个路径下DEFAULT_STRATEGIES_PATH;即DispatcherServlet.properties

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

 配置文件中配置了默认的Resolver, HandlerMapping, HandlerAdapter,  onRefresh()方法中要初始化的组件都有一个默认的配置。

 

上面的组件初始化基本都遵从了一个主要逻辑:先从容器或者资源里找,找不到就使用配置文件中默认配置的。

 

通过上面的代码spring mvc的初始化工作就完成了,上下文容器也就建立了!

 

 

分享到:
评论

相关推荐

    Spring5MVC源码.docx

    【Spring5MVC源码分析】 Spring MVC 是一个基于Java的、用于构建Web应用程序的、高度可插拔的MVC框架,它是Spring Framework的重要组成部分。Spring MVC的核心目标是简化前端控制器的开发,使得开发者可以专注于...

    spring-mvc 基础功能之源码debug

    在IT行业中,Spring MVC是一个广泛使用的Java Web框架,它提供了强大的模型-视图-控制器(MVC)架构来构建Web应用程序。这篇博客“spring-mvc 基础功能之源码debug”似乎深入探讨了Spring MVC的核心功能,并通过源码...

    Spring mvc、 Spring、 Spring jdbc 整合实例源码

    Spring MVC是Spring框架的一部分,专门用于构建Web应用程序。它采用模型-视图-控制器(Model-View-Controller,MVC)架构模式,将业务逻辑、数据处理和用户界面分离,使得应用更加模块化,易于维护。Spring MVC通过...

    看透spring mvc源代码分析与实践扫描版带目录+源码

    Spring MVC是Spring框架的一个核心模块,它用于构建Web应用程序的模型-视图-控制器(MVC)架构。这本书“看透Spring MVC源代码分析与实践”显然是为了帮助开发者深入理解Spring MVC的工作原理,并通过源码分析提升...

    spring mvc 4.0

    15. **兼容性与兼容性测试**:Spring MVC 4.0确保与各种Web容器的兼容性,如Tomcat、Jetty等,并提供了全面的兼容性测试。 以上就是Spring MVC 4.0的主要特点和知识点。这个版本在易用性、性能和功能方面都有显著...

    maven spring mvc示例源码

    【标题】"maven spring mvc示例源码"揭示了这...这个示例源码对于初学者理解Maven与Spring MVC的集成,以及如何构建一个完整的Java Web应用具有很高的参考价值。通过实际操作和调试,开发者可以更深入地掌握这些技术。

    Spring MVC 大型项目源码

    Spring MVC 是一个强大的Java Web开发框架,用于构建高效、可维护和模块化的Web应用程序。...通过分析这个大型项目源码,新手可以了解到Spring MVC的完整生命周期,以及如何组织和管理一个复杂Web应用程序的各个部分。

    spring mvc项目

    可用于分析spring mvc源码、spring mvc父子容器初始化流程、session和cookie机制、spring session等,也可以用于学习Java Web(servlet、filter、listener等)、spring源码等。 该项目使用servlet3.0规范,无web.xml...

    搭建Spring4+Spring MVC web工程的最佳实践 源码.zip

    Spring是个非常非常非常优秀的java框架,主要是用它的IOC容器帮我们依赖注入和管理一些...现在我们就来搭建一个利用Spring和Spring MVC结合的web工程最佳实践的例子。以Spring Framework 4.2.0为例,IDE为Myeclipse。

    OSGI整合Spring、Mybatis、Spring MVC实现一个登录应用案例

    Spring MVC是Spring框架的一部分,用于构建Web应用程序。它处理HTTP请求,将请求映射到控制器,然后通过模型和视图进行响应。在OSGI中,Spring MVC可以被包装成一个bundle,与其他服务协同工作,提供Web接口供用户...

    Spring MVC 实例

    Spring MVC 提供了灵活的处理机制,包括处理器映射、视图解析、数据绑定、本地化和主题支持,以及对 RESTful 风格的 URL 支持,使得开发人员可以轻松地创建功能丰富的、高性能的 Web 应用。 ### 1. MVC 架构模式 ...

    Spring MVC step-by-step 源码

    Spring MVC 是一个强大的Java Web开发框架,用于构建高效、可维护的Web应用程序。它基于Spring框架,提供了模型-视图-控制器(MVC)架构,简化了开发过程。本资源"Spring MVC step-by-step 源码"是针对初学者准备的...

    spring mvc、spring、hibernate、bootstrap 框架整合开发的项目源码下载

    1. Spring MVC:Spring MVC是Spring框架的一部分,专门用于构建Web应用程序的模型-视图-控制器(MVC)架构。它提供了处理HTTP请求、数据绑定、异常处理等功能,并通过DispatcherServlet作为入口点来协调各个组件。...

    Java EE企业级应用开发教程(Spring Spring MVC MyBatis)(黑马程序员编著)

    Spring MVC是Spring框架的一部分,专为Web应用设计。它遵循模型-视图-控制器(MVC)设计模式,将业务逻辑、用户界面和数据访问分离开来。Spring MVC通过DispatcherServlet作为入口点,处理HTTP请求,并根据请求映射...

    Spring MVC+MyBatis整合项目源码

    这个项目源码提供了一个实战学习平台,帮助开发者理解和掌握Spring MVC与MyBatis的整合应用,同时可以了解到如何在实际项目中组织代码结构、配置文件以及进行测试。通过深入研究这些代码,你将能够更好地运用这两个...

    Pro.Spring.MVC.With.Web.Flow.英文版+源码

    《Pro.Spring.MVC.With.Web.Flow》是一本深入探讨Spring MVC框架和Web Flow技术的专业书籍,结合源码分析,为读者提供了全面理解这两种技术的详细路径。Spring MVC是Spring框架的一部分,用于构建高度可维护和可扩展...

    jetty 手动 加载spring mvc demo

    1. **创建Spring配置**:首先,你需要创建一个Spring的配置文件,如`servlet-context.xml`,该文件定义了Spring MVC的组件,如DispatcherServlet、视图解析器和映射路径等。 2. **编写Controller**:接着,编写...

    SSM(Spring +Spring MVC +Mybatis)源码

    **Spring MVC**是Spring框架的一个模块,专门用于构建Web应用程序。它采用模型-视图-控制器(MVC)设计模式,分离了业务逻辑、数据和用户界面。请求由DispatcherServlet处理,然后转发给合适的控制器,控制器处理...

    Servlet,JSP和Spring MVC 初学指南源码

    Spring MVC是Spring框架的一个模块,专为构建Web应用程序设计。它提供了一个模型-视图-控制器(MVC)架构,使得开发者可以更清晰地组织代码,提高代码的可维护性和测试性。Spring MVC通过DispatcherServlet作为前端...

    基于spring mvc、spring、hibernate、bootstrap、maen开发的企业级项目,导入即可运行

    Spring MVC是Spring框架的一个模块,专门用于构建Web应用程序。它提供了一个模型-视图-控制器(MVC)架构,使得开发者可以将业务逻辑、数据处理和用户界面分离,提高代码的可维护性和测试性。在Spring MVC中,...

Global site tag (gtag.js) - Google Analytics