`

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的初始化工作就完成了,上下文容器也就建立了!

 

 

分享到:
评论

相关推荐

    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。

    spring源码分析(1-10)

    Spring源代码解析(二):ioc容器在Web容器中的启动 Spring源代码分析(三):Spring JDBC Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy Spring源代码解析(六):Spring声明式事务处理...

    spring源码分析

    Spring源代码解析(二):ioc容器在Web容器中的启动 3.Spring源代码解析(三):Spring JDBC 4.Spring源代码解析(四):Spring MVC 5.Spring源代码解析(五):Spring AOP获取Proxy 6. Spring源代码解析(六):Spring...

    Spring攻略英文版(附带源码)

    第一部分 核心概念  第1章 控制反转和容器   1.1 使用容器管理组件   1.1.1 问题描述   1.1.2 解决方案   1.1.3 实现方法   1.2 使用服务定位器降低查找组件的复杂性   1.2.1 问题描述   ...

    Spring源码学习文档,绝对值得好好研究~~

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

    javaWEB期末课程大作业问卷调查系统源代码.zip

    Web容器:Apache Tomcat 8.5 项目管理工具:Maven 后端技术:Spring+Spring MVC+MyBatis(SSM框架) 前端技术:LayUI(Vue/React) 技术 数据库:MySQL8.0 数据库设计软件:Power Designer16.5 IDE:IDEA Web容器:...

    Spring源代码解析.rar

    Spring源代码解析2:IoC容器在Web容器中的启动.doc Spring源代码解析3:Spring JDBC .doc Spring源代码解析4:Spring MVC .doc Spring源代码解析5:Spring AOP获取Proxy .doc Spring源代码解析6:Spring声明式事务...

    Spring源代码解析

    Spring源代码解析(二):IoC容器在Web容器中的启动 Spring源代码解析(三):Spring JDBC Spring源代码解析(四):Spring MVC Spring源代码解析(五):Spring AOP获取Proxy Spring源代码解析(六):Spring声明式事务...

    Spring+3.x企业应用开发实战光盘源码(全)

     第2章:通过一个简单的例子展现开发Spring Web应用的整体过程,通过这个实例,读者可以快速跨入Spring Web应用的世界。  第3章:讲解Spring IoC容器的知识,通过具体的实例详细地讲解IoC概念。同时,对Spring框架...

    Spring 源代码解析

    Spring源代码解析2:IoC容器在Web容器中的启动;Spring源代码解析3:Spring JDBC ; Spring源代码解析4:Spring MVC ;Spring源代码解析5:Spring AOP获取Proxy;Spring源代码解析6:Spring声明式事务处理 ; ...

    基于SSM的汽车销售系统(源码+部署说明+演示视频+源码介绍).zip

    Spring负责IOC/AOP容器管理,Spring MVC负责Web层处理,MyBatis负责持久层数据访问。通过这些组件的协同工作,实现了系统的业务逻辑和数据库操作。部署说明:本资源提供了详细的部署说明,包括环境配置、数据库连接...

    spring源代码解析

    简单的说,在web容器中,通过ServletContext为Spring的IOC容器提供宿主环境,对应的建立起一个IOC容器的体系。其中,首先需要建立的是根上下文,这个上下文持有的对象可以有业务对象,数据存取对象,资源,事物管理...

    《精通Spring2.X企业应用开发详解》随书源码1-15章

    动态语言支持 第5篇 展现层应用 第19章 Spring MVC之一 第20章 Spring MVC之二 第21章 集成其他Web框架 第6篇 其他 第22章 Spring应用的测试 第23章 Spring工具类盘点 附录A 各种数据库连接...

    xmljava系统源码-springframework-source-5.1.x:这是一个注释版的Spring源码分析工程,版本为5.1.x,

    提供了Spring容器的支持,扩展了BeanFactory,提供了Spring中Bean生命周期的支持,在bean创建完成之后, 也是由该模块负责来维护bean和bean之间的依赖关系。常用的ApplicationContext核心接口也是该模块中所支持的;...

    Spring技术内幕:深入解析Spring架构与设计原理(第2部分)

     Spring如何在Web环境中集成IoC容器并为Web应用开发提供利器?  我们耳熟能详的MVC模式在Spring中是如何实现的?  Spring MVC如何灵活地集成各种丰富的视图展现方案?  Spring实现远端调用的方案有很多种,你...

    SPRING3技术内幕

     Spring如何在Web环境中集成IoC容器并为Web应用开发提供利器?  我们耳熟能详的MVC模式在Spring中是如何实现的?  Spring MVC如何灵活地集成各种丰富的视图展现方案?  Spring实现远端调用的方案有很多种,你...

    Spring技术内幕:深入解析Spring架构与设计原理

     spring如何在web环境中集成ioc容器并为web应用开发提供利器?  我们耳熟能详的mvc模式在spring中是如何实现的?  spring mvc如何灵活地集成各种丰富的视图展现方案?  spring实现远端调用的方案有很多种,你...

    项目管理源码java传统开发

    是以Spring Framework为核心容器,Spring MVC为模型视图控制器,Mybatis为数据访问层, Apache Shiro为权限授权层,Ehcahe对常用数据进行缓存,Disruptor作为并发框架,Bootstrap作为前端框架的优秀开源系统。

Global site tag (gtag.js) - Google Analytics