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的核心机制和设计理念。Spring作为Java领域最为广泛应用的框架之一,其源码的深入理解对于开发者来说至关重要。这篇...
《Spring源码解析》PDF是一份深入探讨Spring框架核心机制的文档,主要涵盖了Spring的IoC容器、JDBC、MVC、AOP、声明式事务处理、与Hibernate的集成以及Acegi(现为Spring Security)框架的鉴权和授权等多个关键模块...
《深入剖析Spring Web源码》(第二版) 是一本针对Java开发者深度解析Spring Web框架核心原理的权威指南。这本书详细解读了Spring MVC和Spring WebFlux两大核心模块的源码,帮助读者理解Spring如何实现高效的Web应用...
在"spring源码解析"的资料中,我们可能会深入探讨以下几个关键知识点: 1. **IoC(Inversion of Control,控制反转)与DI(Dependency Injection,依赖注入)**:这是Spring的核心特性,它通过反转对象的创建和管理...
3. **Spring MVC**:Spring用于构建Web应用的模块,包括DispatcherServlet、Model-View-Controller模式的应用,以及视图解析器和处理器映射器的使用。 4. **数据访问集成**:Spring对JDBC、ORM(如Hibernate、...
《Spring源码深度解析》 在Java开发领域,Spring框架无疑是最重要的组件之一,它以其强大的功能和灵活性赢得了广大开发者的心。深入理解Spring源码对于提升开发能力、优化系统设计以及解决实际问题至关重要。本文将...
在源码分析的过程中,读者会深入理解Spring的内部工作机制,例如如何解析配置、如何创建bean实例、如何实现AOP代理等。这将有助于开发者编写更高效、更健壮的代码,也能为参与Spring的扩展或定制打下坚实基础。 总...
总的来说,这份"Java Spring 源码解析 Xmind 思维导图"涵盖了Spring框架的核心组件和设计理念,帮助开发者从源码层面理解Spring的运行机制。通过这样的学习,可以提升开发者对Spring的理解,从而更好地利用Spring...
《Spring源码深入解析》是一本深度探讨Spring框架核心机制的文档,主要针对Spring5版本...文档《Spring源码解析-tom.docx》应包含了上述各方面的详细解读,对于希望深入了解Spring的开发者来说,是一份宝贵的参考资料。
源码深度解析对于开发者来说,是理解Spring工作原理、提升技术水平的重要途径。本资源提供了完整的Spring源码,附带注释和实例,对初学者极其友好。 首先,我们来探讨Spring的核心模块: 1. **IoC容器**:Spring的...
学习Spring源码有助于深入理解其内部工作原理,例如bean的生命周期管理、AOP的实现、以及MVC的请求处理流程。这将有助于开发者更高效地利用Spring框架,编写出高质量、高性能的Java应用。通过分析源码,开发者还可以...
Spring 3.2的DispatcherServlet也更加强大,支持异步处理和多视图解析策略。 Spring 3.2对数据访问层提供了全面支持,包括JDBC、ORM(Object-Relational Mapping)框架如Hibernate和MyBatis。它引入了新的...
源码中展示了DispatcherServlet如何分发请求,HandlerMapping如何映射请求到处理器,以及ModelAndView如何封装视图数据。同时,你还可以研究视图解析器和模板引擎的实现,例如JSP、FreeMarker或Thymeleaf。 此外,...
同时,还包含了部分Spring MVC的源码解析,这对于学习框架的工作原理极其宝贵。 1. **Spring MVC架构**:Spring MVC的核心组件包括DispatcherServlet、Controller、Model、View和ViewResolver等。DispatcherServlet...
DispatcherServlet、Controller、ModelAndView等组件构成了Spring MVC的核心。 6. **Spring Boot** Spring Boot是Spring的现代化启动器,它通过预配置的“起步依赖”(Starter POMs)简化了新项目的创建。Spring ...
Spring Security是强大的安全框架,源码解析可以帮助理解权限控制、认证和授权的实现。例如,FilterSecurityInterceptor和AccessDecisionManager等关键组件的工作方式。 通过对Spring框架源码的深度解析,开发者...
包括`spring-context`、`spring-webmvc`、`spring-web`、`spring-beans`、`spring-core`、`spring-jdbc`、`spring-aop`、`spring-tx`、`spring-jms`以及`spring-expression`,通过源码解析,揭示其内部机制和设计...
本文将通过对Spring源码的深入解析,逐一探讨这些核心组件的工作原理。 首先,我们关注Spring的事务处理。在Spring中,事务管理是通过声明式和编程式两种方式实现的。声明式事务管理基于XML配置或注解,使得开发者...