`

spring DispatcherServlet源码解析

 
阅读更多

DispatcherServlet继承FrameworkServlet,FrameworkServlet继承HttpServletBean,HttpServletBean继承HttpServlet,Web容器(比如Resin、Tomcat)启动时是调用HttpServlet的init方法初始化Servlet,HttpServletBean重写了init方法:

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, this.environment));
			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");
		}
	}

 FrameworkServlet重写了initServletBean方法:

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");
		}
	}

 在initWebApplicationContext方法会从ServletContext中获取由ContextLoadListener加载的WebApplicationContext对象,然后调用createWebApplicationContext方法实例化一个XmlWebApplicationContext,并将Listener加载的context作为该context的parent:

protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
		Class<?> contextClass = getContextClass();
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Servlet with name '" + getServletName() +
					"' will try to create custom WebApplicationContext context of class '" +
					contextClass.getName() + "'" + ", using parent context [" + parent + "]");
		}
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + contextClass.getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		wac.setParent(parent);
		wac.setConfigLocation(getContextConfigLocation());

		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}

 

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			if (this.contextId != null) {
				wac.setId(this.contextId);
			}
			else {
				// Generate default id...
				ServletContext sc = getServletContext();
				if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
					// Servlet <= 2.4: resort to name specified in web.xml, if any.
					String servletContextName = sc.getServletContextName();
					if (servletContextName != null) {
						wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName +
								"." + getServletName());
					}
					else {
						wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + getServletName());
					}
				}
				else {
					// Servlet 2.5's getContextPath available!
					wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
							ObjectUtils.getDisplayString(sc.getContextPath()) + "/" + getServletName());
				}
			}
		}

		wac.setServletContext(getServletContext());
		wac.setServletConfig(getServletConfig());
		wac.setNamespace(getNamespace());
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

		postProcessWebApplicationContext(wac);

		applyInitializers(wac);

		wac.refresh();
	}

 在这个方法中又看到了熟悉的refresh方法,下面的过程跟IOC的初始化过程一样。

在该方法中设置了namespace属性,而namespace属性的默认值是’servletName‘-servlet,IOC初始化中会去加载资源文件:

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}

 

protected String[] getConfigLocations() {
		return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
	}

 

protected String[] getDefaultConfigLocations() {
		if (getNamespace() != null) {
			return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
		}
		else {
			return new String[] {DEFAULT_CONFIG_LOCATION};
		}
	}

 从这个流程可以看出如果没有显示指定contextConfigLocation,就会使用namespace的值作为配置文件来加载。

通过DispatcherServlet创建的context最终会放到ServletContext的attribute中,key是FrameworkServlet.class.getName() + ".CONTEXT." + getServletName()

 

分享到:
评论

相关推荐

    Spring5 源码分析(第 2 版)-某Tom老师

    《Spring5 源码分析(第 2 版)》是某Tom老师精心编写的深度解析文档,旨在帮助读者全面理解Spring5的核心机制和设计理念。Spring作为Java领域最为广泛应用的框架之一,其源码的深入理解对于开发者来说至关重要。这篇...

    spring源码解析 pdf

    《Spring源码解析》PDF是一份深入探讨Spring框架核心机制的文档,主要涵盖了Spring的IoC容器、JDBC、MVC、AOP、声明式事务处理、与Hibernate的集成以及Acegi(现为Spring Security)框架的鉴权和授权等多个关键模块...

    深入剖析Spring Web源码 pdf高清版(第二版)

    《深入剖析Spring Web源码》(第二版) 是一本针对Java开发者深度解析Spring Web框架核心原理的权威指南。这本书详细解读了Spring MVC和Spring WebFlux两大核心模块的源码,帮助读者理解Spring如何实现高效的Web应用...

    spring源码解析

    在"spring源码解析"的资料中,我们可能会深入探讨以下几个关键知识点: 1. **IoC(Inversion of Control,控制反转)与DI(Dependency Injection,依赖注入)**:这是Spring的核心特性,它通过反转对象的创建和管理...

    spring源码解析和mybatis学习

    3. **Spring MVC**:Spring用于构建Web应用的模块,包括DispatcherServlet、Model-View-Controller模式的应用,以及视图解析器和处理器映射器的使用。 4. **数据访问集成**:Spring对JDBC、ORM(如Hibernate、...

    Spring源码解析

    《Spring源码深度解析》 在Java开发领域,Spring框架无疑是最重要的组件之一,它以其强大的功能和灵活性赢得了广大开发者的心。深入理解Spring源码对于提升开发能力、优化系统设计以及解决实际问题至关重要。本文将...

    spring 源码中文注释

    在源码分析的过程中,读者会深入理解Spring的内部工作机制,例如如何解析配置、如何创建bean实例、如何实现AOP代理等。这将有助于开发者编写更高效、更健壮的代码,也能为参与Spring的扩展或定制打下坚实基础。 总...

    Java Spring 源码解析 Xmind 思维导图

    总的来说,这份"Java Spring 源码解析 Xmind 思维导图"涵盖了Spring框架的核心组件和设计理念,帮助开发者从源码层面理解Spring的运行机制。通过这样的学习,可以提升开发者对Spring的理解,从而更好地利用Spring...

    spring源码深入解析

    《Spring源码深入解析》是一本深度探讨Spring框架核心机制的文档,主要针对Spring5版本...文档《Spring源码解析-tom.docx》应包含了上述各方面的详细解读,对于希望深入了解Spring的开发者来说,是一份宝贵的参考资料。

    spring源码深度解析(包含所有spring源码,带全部的注释以及案例,很适合入门级)

    源码深度解析对于开发者来说,是理解Spring工作原理、提升技术水平的重要途径。本资源提供了完整的Spring源码,附带注释和实例,对初学者极其友好。 首先,我们来探讨Spring的核心模块: 1. **IoC容器**:Spring的...

    spring源码

    学习Spring源码有助于深入理解其内部工作原理,例如bean的生命周期管理、AOP的实现、以及MVC的请求处理流程。这将有助于开发者更高效地利用Spring框架,编写出高质量、高性能的Java应用。通过分析源码,开发者还可以...

    spring3.2源码包

    Spring 3.2的DispatcherServlet也更加强大,支持异步处理和多视图解析策略。 Spring 3.2对数据访问层提供了全面支持,包括JDBC、ORM(Object-Relational Mapping)框架如Hibernate和MyBatis。它引入了新的...

    spring 框架源码 版本:5.2.9.RELEASE

    源码中展示了DispatcherServlet如何分发请求,HandlerMapping如何映射请求到处理器,以及ModelAndView如何封装视图数据。同时,你还可以研究视图解析器和模板引擎的实现,例如JSP、FreeMarker或Thymeleaf。 此外,...

    Spring MVC 项目+ 源码解析

    同时,还包含了部分Spring MVC的源码解析,这对于学习框架的工作原理极其宝贵。 1. **Spring MVC架构**:Spring MVC的核心组件包括DispatcherServlet、Controller、Model、View和ViewResolver等。DispatcherServlet...

    spring 源代码解析.zip

    DispatcherServlet、Controller、ModelAndView等组件构成了Spring MVC的核心。 6. **Spring Boot** Spring Boot是Spring的现代化启动器,它通过预配置的“起步依赖”(Starter POMs)简化了新项目的创建。Spring ...

    Spring+源码+深度解析

    Spring Security是强大的安全框架,源码解析可以帮助理解权限控制、认证和授权的实现。例如,FilterSecurityInterceptor和AccessDecisionManager等关键组件的工作方式。 通过对Spring框架源码的深度解析,开发者...

    spring源码包.zip

    包括`spring-context`、`spring-webmvc`、`spring-web`、`spring-beans`、`spring-core`、`spring-jdbc`、`spring-aop`、`spring-tx`、`spring-jms`以及`spring-expression`,通过源码解析,揭示其内部机制和设计...

    spring源码分析

    本文将通过对Spring源码的深入解析,逐一探讨这些核心组件的工作原理。 首先,我们关注Spring的事务处理。在Spring中,事务管理是通过声明式和编程式两种方式实现的。声明式事务管理基于XML配置或注解,使得开发者...

Global site tag (gtag.js) - Google Analytics