文章一直更新中......

众所周知,Spring mvc 将所有请求都在 DispatcherServlet 中处理,并且配置有一个监听器

在源码了解之前,我们需要知道的是服务器启动时候,listener filter servlet 执行顺序:---.大家可以自己去测试

                        1.listener 2.filter 3.servlet 

 

(一).所以我们第一步先看一看监听器listener 做了什么事情?

 

1.实现了 ServletContextListener 接口 ,用监听servletcontext的动作
2.继承了ContextLoader ,执行根应用程序的上下文实际的初始化工作被 ContextLoaderListener(我们的监听器)所调用

 所以在服务器启动时候,率先进行了 invoke initWebApplicationContext()  method;

我们点进去看一看它的实现

因为是初始化--先进行了判断保证我们的servletcontext 是一个干净的servletcontext 

 

 

执行流程:
1.private
WebApplicationContext context;
初始化是null;

2.在createWebApplicationCotext()方法中 成员变量 context 被实例化为 class org.springframework.web.context.support.XmlWebApplicationContext 类型,这个类型实现了 ConfigurableWebApplicationContext 接口,也是必须要实现的;

ConfigurableWebApplicationContext 接口的描述:

 *Interface to be implemented by configurable web application contexts.

 * Supported by {@link ContextLoader} and

 * {@link org.springframework.web.servlet.FrameworkServlet}.

 *该接口由可配置的web 上下文所实现,对contextloader(监听器) frameworkservlet(servlet 容器)有支持,可以得知该接口专门为web 打造的;

3.isActive() 方法: 翻译看源码,我们并没有进行刷新的操作,所以返回默认值false

/**
     * Determine whether this application context is active, that is,
     * whether it has been refreshed at least once and has not been closed yet.
     * @return whether the context is still active
     * @see #refresh()
     * @see #close()
     * @see #getBeanFactory()
     */
  确定是否这个应用上下文处于活动状态,也就是说它至少被刷新过一次,并尚未关闭
boolean isActive();

4.configureAndRefreshWebApplicationContext():完成bean 的解析,加载,初始化,很重要的操作;

只一步主要就是 refresh() 操作:
  源码对此方法对解释
/**

* Load or refresh the persistent representation of the configuration,

* which might an XML file, properties file, or relational database schema.

* <p>As this is a startup method, it should destroy already created singletons

* if it fails, to avoid dangling resources. In other words, after invocation

* of that method, either all or no singletons at all should be instantiated.

* @throws BeansException if the bean factory could not be initialized

* @throws IllegalStateException if already initialized and multiple refresh

* attempts are not supported

*/
可以持久化的加载或者刷新配置文件,可能是XML 文件,也可能是properties 文件,或者是关系型数据库的模式
作为启动的方法,如果启动失败,他应该销毁已经创建的单例,去避免挂起资源; 换句话说,在调用这个方法后,所有实例化的和不实例化的
都应该被实例化
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // Check for listener beans and register them.
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }
        }
    }

 

其中主要就是第2部和第11部:

obtainFreshBeanFactory():进行解析我们的xml 以及我们自定义的xml 标签,每一个<bean> 都是 BeanDefinitions对象,里面维护了bean的一些详细信息,方便实例化

注意,这一步并没有实例化bean ,只是解析XML ,将所有的eanDefinitions对象都放入了 beanDefinitionMap中;我们看它的实现

    (-)使用默认的bean工厂DefaultListableBeanFactory, loadBeanDefinitions(beanFactory)

   (二).使用XmlBean解析器去解析xml bean definition 

   (三). 注册bean

  (四).这一步很重要了,开始干活了,解析xml  

  (五).循环遍历查找使用哪一种解析器,像一些默认的标签bean,alias,import,beans 会进入第一个方法;

    像context ,aspect,dubbo 这种标签是属于自定义标签,只要符合Spring 规则就可以加载进行加载;下面我会说;

  我们先看parseDefaultElement(ele,delegate)方法:

  是不是提供了默认的标签bean,alias,import,beans的解析:

我们看它解析bean 的实现;源码多,具体需要自己去看,就是拿到,ID class 等信息:

bdholder 是一个装饰类,里面拿到了bean的所有信息

注册bean 

注册bean: 

 

点进去可以看到:其实就是将bean 的信息对象注册到我们DefaultListableBeanFactory 工厂维护的beanDefinitionMap中;名字放入了List<String> beanDefinitionNames 中

 

 

这里bean 的注册就完成了; 

(六)关于自定义的XML 标签解析,也是Spring很有魅力的一个地方,像一些aop 标签,dubbo 标签都是通过自定义解析器去实现的,当然要遵循Spring 解析配置规则

才会被Spring扫描解析到,那么如何让才能让Spring解析我们自定义的标签呢?

      以Spring-aop 包为例: 1.定义spring.handlers :键值对,里面存放的是我们组册解析我们自定义XML的类,有我们自己实现,会被反射实例化执行里面的方法,

                 2.spring.schemas :我们XML 所遵循的schemas,如果schemas地址是无效的,请META-INF目录下放入自己的xsd文件

 

    看Spring 解析方法:handler 就是在Spring.handlers 对应的被反射实例化的对象,parse 方法就是对自定义标签的解析

实例化并调用init ,init 方法是将标签的属性进行注册存放到map 中,由parse 方法去获取并对应解析

 自定义解析请看link:https://www.cnblogs.com/iscys/p/9905608.html


1.spring 加载的时候,使用的bean 工厂 是默认的 DefaultListableBeanFactory 对象
2.工厂内部维护着 Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);beanmap
3.解析XML 时候,会分别识别bean 标签,import标签,alias 标签,beans 标签并做不同的判断 注册bean时候调用了registerBeanDefinition()将bean 注册到 beanDefinitionMap中
    beanDefinitionMap.put(beanName, beanDefinition);

 关于第11步,是很重要的,会完成bean 的实例化,以及自定义InitializingBean aware 的接口实现的调用,

   我单独写了文章;link:https://www.cnblogs.com/iscys/p/9903766.html

5.将 this.context 即XmlWebApplicationContext 放入servletContext上下文中,servlet 可以进行共享此applicattioncontext,以此达到共享bean 的目的

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

扩展:我们可以通过得知监听器给我们创建的applicationcontext 的类型
  WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());
  
  System.out.println(rootContext.getClass());

 

 

 

 

 

 

 

 

 

二).Servlet 的实现 

我们看一看它的类层次结构:DispatcherServlet--->  FrameworkServlet-->  HttpServletBean ---> HttpServlet 

可以得知底层其实实现了HttpServlet,其实就是一个servlet

 

给大家翻译一下 DispatcherServlet 文档:
/**
 * Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers or HTTP-based remote service
 * exporters. Dispatches to registered handlers for processing a web request, providing convenient mapping and exception
 * handling facilities.
 
处理http 请求处理器和控制器的中央调度器,例如,用于web ui 控制器或者基于http的远程;调度注册的处理程序为web 请求
提供便利的映射和异常处理;
* <p>This servlet is very flexible: It can be used with just about any workflow, with the installation of the * appropriate adapter classes. It offers the following functionality that distinguishes it from other request-driven * web MVC frameworks:
这个servlet 是非常精巧的:它几乎可以被任何的工作流所使用,只要安装了合适的适配器类,它提供了如下功能使之区别其他请求驱动的web mvc 框架

* <ul> <li>It is based around a JavaBeans configuration mechanism.
它是基于java bean 的配置机制的 * * <li>It can use any {@link HandlerMapping} implementation - pre-built or provided as part of an application - to * control the routing of requests to handler objects. Default is {@link org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping} * and {@link org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping}. HandlerMapping objects * can be defined as beans in the servlet's application context, implementing the HandlerMapping interface, overriding * the default HandlerMapping if present. HandlerMappings can be given any bean name (they are tested by type).
它可以使用基于handlermapping 的实现,提前构建或者提供作为应用程序的一部分,来控制请求到处理对象之间的路由;默认提供了beannameurlhandlermapping
以及default annotationmapping ;处理器映射器对象可以被定义作为servlet 上下问对象的bean ;实现handlermapping 接口,覆盖默认的handlempping
handlermapping 会被赋予一个bean 名字;
* <li>It can use any {@link HandlerAdapter}; this allows for using any handler interface. Default adapters are {@link * org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter}, {@link org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter}, * for Spring's {@link org.springframework.web.HttpRequestHandler} and {@link org.springframework.web.servlet.mvc.Controller} * interfaces, respectively. A default {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} * will be registered as well. HandlerAdapter objects can be added as beans in the application context, overriding the * default HandlerAdapters. Like HandlerMappings, HandlerAdapters can be given any bean name (they are tested by type). 它可以使用一些处理器适配器;它允许使用任何处理接口
默认的适配器是 HttpRequestHandlerAdapter,simplecontrollerhandleradapter分别对应着 HttpRequestHandler,Controller handler接口
默认的annotationhandler也会被注册 处理器适配器对象也会在application 上下文加载进来为bean

 * <li>The dispatcher's exception resolution strategy can be specified via a {@link HandlerExceptionResolver}, for
 * example mapping certain exceptions to error pages. Default are
 * {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver},
 * {@link org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver}, and
 * {@link org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver}. These HandlerExceptionResolvers can be overridden
 * through the application context. HandlerExceptionResolver can be given any bean name (they are tested by type).
 *
 * <li>Its view resolution strategy can be specified via a {@link ViewResolver} implementation, resolving symbolic view
 * names into View objects. Default is {@link org.springframework.web.servlet.view.InternalResourceViewResolver}.
 * ViewResolver objects can be added as beans in the application context, overriding the default ViewResolver.
 * ViewResolvers can be given any bean name (they are tested by type).
 *
 * <li>If a {@link View} or view name is not supplied by the user, then the configured {@link
 * RequestToViewNameTranslator} will translate the current request into a view name. The corresponding bean name is
 * "viewNameTranslator"; the default is {@link org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator}.
 *
 * <li>The dispatcher's strategy for resolving multipart requests is determined by a {@link
 * org.springframework.web.multipart.MultipartResolver} implementation. Implementations for Jakarta Commons FileUpload
 * and Jason Hunter's COS are included; the typical choise is {@link org.springframework.web.multipart.commons.CommonsMultipartResolver}.
 * The MultipartResolver bean name is "multipartResolver"; default is none.
 *
 * <li>Its locale resolution strategy is determined by a {@link LocaleResolver}. Out-of-the-box implementations work via
 * HTTP accept header, cookie, or session. The LocaleResolver bean name is "localeResolver"; default is {@link
 * org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver}.
 *
 * <li>Its theme resolution strategy is determined by a {@link ThemeResolver}. Implementations for a fixed theme and for
 * cookie and session storage are included. The ThemeResolver bean name is "themeResolver"; default is {@link
 * org.springframework.web.servlet.theme.FixedThemeResolver}. </ul>
 *
 * <p><b>NOTE: The {@code @RequestMapping} annotation will only be processed if a corresponding
 * {@code HandlerMapping} (for type level annotations) and/or {@code HandlerAdapter} (for method level
 * annotations) is present in the dispatcher.</b> This is the case by default. However, if you are defining custom
 * {@code HandlerMappings} or {@code HandlerAdapters}, then you need to make sure that a corresponding custom
 * {@code DefaultAnnotationHandlerMapping} and/or {@code AnnotationMethodHandlerAdapter} is defined as well -
 * provided that you intend to use {@code @RequestMapping}.
 *
 * <p><b>A web application can define any number of DispatcherServlets.</b> Each servlet will operate in its own
 * namespace, loading its own application context with mappings, handlers, etc. Only the root application context as
 * loaded by {@link org.springframework.web.context.ContextLoaderListener}, if any, will be shared.
 *
 * <p>As of Spring 3.1, {@code DispatcherServlet} may now be injected with a web
 * application context, rather than creating its own internally. This is useful in Servlet
 * 3.0+ environments, which support programmatic registration of servlet instances. See
 * {@link #DispatcherServlet(WebApplicationContext)} Javadoc for details.
 *

 

 

 

其实根据上一篇对servlet 详解,我们知道对于servlet 的初始化动作一定放在init 方法中,设置start 等级,这样就可以服务器启动,初始化servlet

 

/**
     * Map config parameters onto bean properties of this servlet, and
     * invoke subclass initialization.
     * @throws ServletException if bean properties are invalid (or required
     * properties are missing), or if subclass initialization fails.
     */
将文件配置参数映射到servlet 的bean 属性上,并调用子类初始化;
@Override public final void init() throws ServletException {

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 关于我们的请求是经过什么的过程呢?下面这张图就是它的执行流程,网上一堆,那么我一个一个的给大家解析跟随源代码;你就不会迷茫了;

 

 

1.发送请求,这个就不用说了,哈哈,地址栏回车;接下来就是我们的DispatcherServlet操作了

2.映射处理器:熟悉servlet 都知道,请求第一步进入doService(request,response) 方法 ,就是这个方法。

  里面会有一个doDispatch() ;这个我们可以理解为方法入口,进行分发 ;

 

所有的方法执行都在doDispatch()中;我们看一看获取HandlerMapping,就是这个方法,通过request 请求得到mappedHandler,是个 HandlerExecutionChain

执行链: 

 确定一个handler通过我们的request请求; 

我们看一看getHandler()方法:会遍历我们注册过的handlermapping(handlerMapping是在初始化注册的) ;

执行getHandler(request);往后面点,可以看到它会根据地址去我们的urlMap中去找HandlerMethod ,就是执行这个url

所匹配的类名和方法;后期会被反射调用;

去看有没有拦截器之类的,并返回执行链: 

其实可以得出,这个执行链就是一些需要执行方法的链路,就是一些类方法组成的;如下:

HandlerExecutionChain with handler [public void com.thirdparty.controller.gzh.WxConnectionController.wxConnection(javax.servlet.http.HttpServletResponse,java.lang.String,java.lang.String,java.lang.String,java.lang.String) throws java.lang.Exception] and 1 interceptor

到这里handlerMapping 就结束了并返回执行链; 

3.开始获得处理器适配器; 得到执行链中的需要执行的methodhandler来匹配HandlerAdapter;

得到HandlerAdapter ,我们就可以通过这个适配器 去执行里面的方法;看第四步;

4.关键的方法调用就来了,通过反射调用执行的方法,返回ModelAndView 

 

方法调用: 

Java 反射:

  

这样,其实方法就执行完了;

5.视图解析 

posted on 2018-10-08 19:42  iscys  阅读(250)  评论(0编辑  收藏  举报