- 浏览: 22796 次
- 性别:
- 来自: 沈阳
文章分类
Spring中MVC框架的底层实现
Spring中MVC框架的底层实现
Written by Tony Jiang @ 20120119
Spring中的MVC
Spring MVC的流程
Spring的Sample这里就不讲了,大家自己上网google
Spring 在Web环境下的启动
按照javaEE标准,Web应用启动web.xml,之后的启动root是ServletContextListener。
(问题: ContextListener如何启动? 随着web容器启动而启动?是单线程的?线程安全的?)
ContextListener是随着Tomcat的启动而启动,并且只启动这一次,为整个WebContext的启动做准备。
Spring在Web环境下启动的监听器是:
[java] view plaincopyprint?
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
/**
* Initialize the root web application context.
*/
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
其中WebApplication的上下文在ContextLoader中初期化
[java] view plaincopyprint?
/**
* Initialize Spring's web application context for the given servlet context,
* using the application context provided at construction time, or creating a new one
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
* @param servletContext current servlet context
* @return the new WebApplicationContext
* @see #ContextLoader(WebApplicationContext)
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
最后的启动委托给XmlWebApplicationContext
这个类中使用了大量的模板设计模式!!
最终的容器启动和我们编程式启动Spring类同
[java] view plaincopyprint?
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
protected 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(this.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);
}
入口的DispatchServlet
DispatchServlet的初期化和生成,我认为不是由Spring容器负责的,应该是由Web容器自己管理的。可以参考《How tomcat works》这本书
DispatchServlet的init方法在父类的父类的HttpServletBean中
是一个final方法哦
[java] view plaincopyprint?
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");
}
}
真正的servlet的初期化在子类中执行,又是模板模式~~~
于是我们在子类的FrameworkServlet中看到
[java] view plaincopyprint?
/**
* Overridden method of {@link HttpServletBean}, invoked after any bean properties
* have been set. Creates this servlet's WebApplicationContext.
*/
@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");
}
}
接下来最后将自己sevlet对应上具体的ServletContext
先回顾一下Servlet的生存周期
Servlet的init方法是在容器的启动中被启动,只执行这一次。
那就意味着,Servlet的所需要的资源,内存空间,instance的预实例化都要在init内完成。
作为Spring Servlet的init,那么相对应ServletName -servlet.xml中所有的定义类都必须在init中被成功初期化。
我们拿一个简单ServletName -servlet.xml来举例
[html] view plaincopyprint?
1 <?xml version="1.0" encoding="UTF-8" ?>
2 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
3
4 <beans>
5
6 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
7 <property name="prefix" value="/WEB-INF/jsp/" />
8 <property name="suffix" value=".jsp" />
9 </bean>
10
11 <bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
12 <property name="mappings">
13 <props>
14 <prop key="/hello.do">helloController</prop>
15 </props>
16 </property>
17 </bean>
18
19 <bean id="helloController" class="com.ideawu.HelloController">
20 <!--
21 <property name="helloManager" ref="helloManager" />
22 -->
23 </bean>
24
25 </beans>
其中包括viewResolver(采用何种视图模板),HandlerMapping(采用何种http拦截器),Controller(对应每种http请求采用何种控制器)。
所有的这些,都是通过Spring容器本身进行加载的。
DispatchServlet中这些资源的加载是在本身的initStrategies方法内执行(通过父类模板方法的调用)
[java] view plaincopyprint?
/**
* 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);
}
关于HandlerMapping
handlerMaper是一个单例的(相对于一个JVM而言)的ArrayList
它的初期化在DispatchServlet中
[java] view plaincopyprint?
/**
* Initialize the HandlerMappings used by this class.
* <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
* we default to BeanNameUrlHandlerMapping.
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
OrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
它的被执行是在DispatchServlet中的doService中
[java] view plaincopyprint?
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or <code>null</code> if no handler could be found
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
最后会调用到父类AbstractHandlerMapping中的getHandler,返回一个HandlerChain(责任链模式)
[java] view plaincopyprint?
/**
* Look up a handler for the given request, falling back to the default
* handler if no specific one is found.
* @param request current HTTP request
* @return the corresponding handler instance, or the default handler
* @see #getHandlerInternal
*/
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
return getHandlerExecutionChain(handler, request);
}
HandlerChain中包含了一系列封装Controller的HandlerAdapte
在接到http请求之后,在HandlerChain中就能找到自己所要执行的控制器。
其他细节在此打住。
相关推荐
Servlet 和JSP 是Java Web 应用开发的底层技术,而Spring MVC 是Spring 框架中用于解决Servlet 和JSP 应用开发的常见和通用问题的一个模块。Spring MVC 是一个广泛应用于GUI 开发的设计模式,是目前业界主流的Web ...
没事可以练练手,底层jpa注解实现,spring管理bean,spring mvc框架,是一个不错的练手练习。
系统理解Spring MVC框架,为灵活开发高质量产品打下坚实基础。 深入理解Spring MVC的编程技巧和设计理念,提高综合思考、整体架构的能力。 学习作者自研的源代码分析方法——器用分析法,高效学习程序源代码。
第6章:我们从Spring AOP的底层实现技术入手,一步步深入到Spring AOP的内核中,分析它的底层结构和具体实现。 第7章:对如何使用基于AspectJ配置AOP的知识进行了深入的分析,这包括使用XML Schema配置文件、...
使用 Spring 可插入的 MVC架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架。 SpringMVC执行流程概括 SpringMVC框架固然强大,但是其执行流程更是妙不可言。所以我们...
系统理解Spring MVC框架,为灵活开发高质量产品打下坚实基础。 深入理解Spring MVC的编程技巧和设计理念,提高综合思考、整体架构的能力。 学习作者自研的源代码分析方法——器用分析法,高效学习程序源代码。
系统理解Spring MVC框架,为灵活开发高质量产品打下坚实基础。 深入理解Spring MVC的编程技巧和设计理念,提高综合思考、整体架构的能力。 学习作者自研的源代码分析方法——器用分析法,高效学习程序源代码。
在大型网站和复杂系统的开发中,Java具有天然的优势,而在Java的Web框架中Spring MVC以其强大的功能以及简单且灵活的用法受到越来越多开发者的青睐。本书不仅详细地分析Spring MVC的结构及其实现细节,而且讲解网站...
13.1.2. Spring Web MVC框架的特点 13.2. DispatcherServlet 13.3. 控制器 13.3.1. AbstractController 和 WebContentGenerator 13.3.2. 其它的简单控制器 13.3.3. MultiActionController 13.3.4. 命令控制器 13.4. ...
13.1.2. Spring Web MVC框架的特点 13.2. DispatcherServlet 13.3. 控制器 13.3.1. AbstractController 和 WebContentGenerator 13.3.2. 其它的简单控制器 13.3.3. MultiActionController 13.3.4. 命令控制器 ...
Spring Framework 是一种轻量级的解决方案,是构建你的企业级应用程序的潜在一站式解决 方案。 尽管如此, Spring 是模块化的,允许你只...它提供了一个全功能的 MVC 框架,并使你能够将 AOP 透明地集成到你的软件中
Spring MVC以DispatcherServlet为核心,众多组件如HandlerMapping为辅助,为用户封装了请求映射等底层逻辑,让用户可以更专注与业务逻辑的处理。本文会对Spring MVC整体结构做简单介绍。 Spring MVC结构图 Spring ...
(4)集成的框架有:spring mvc + spring + hibernate + logback + junit,spring mvc、hibernate已经用注解配置方式替代 了传统的xml配置方式。 (5)logback在本项目中已经设置了一个aop切面,对所有的controller请求...
第6章:我们从Spring AOP的底层实现技术入手,一步步深入到Spring AOP的内核中,分析它的底层结构和具体实现。 第7章:对如何使用基于AspectJ配置AOP的知识进行了深入的分析,这包括使用XML Schema配置文件、...
Struts只是一个MVC框架(Framework),用于快速开发Java Web应用。Struts实现的重点在C(Controller),包括ActionServlet/RequestProcessor和我们定制的 Action,也为V(View)提供了一系列定制标签(Custom Tag)。但...
通过手写一个五脏俱全的minispringmvc。可以快速理解springmvc的底层实现原理。面试加分哦.用maven导入
13.1.2. Spring Web MVC框架的特点 13.2. DispatcherServlet 13.3. 控制器 13.3.1. AbstractController 和 WebContentGenerator 13.3.2. 其它的简单控制器 13.3.3. MultiActionController 13.3.4. 命令控制器 ...
对于springmvc框架的分析,以及详细的讲解,适合新手,底层技术的实现!