看过spring源码吗_thinkphp源码分析

看过spring源码吗_thinkphp源码分析概述

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

一、概述

  • 对于大多数第一次看spring源码的人来说,都会感觉不知从哪开始看起,因为spring项目源码由多个子项目组成,如spring-beans,spring-context,spring-core,spring-aop,spring-web,spring-webmvc等,整个项目结构如图:
    在这里插入图片描述
  • 可能有人会觉得,既然spring是一个IOC容器或者说是一个bean的容器,那么应该从spring-beans看起,先了解spring是如何从xml文件配置获取需要创建的bean的信息,但是这里有个问题就是虽然知道怎么遍历初始化,但是不知道哪里用到或者说哪里让这些初始化开始,而且像BeanFactory,FactoryBean,Environment,PropertySource等接口还是比较抽象的,比较难看懂,所以很容易让人感觉枯燥,然后就放弃了。
  • 我们可以换个思路,从能接触到的角度开始,即我们通常会使用spring-mvc来进行web开发,如@Controller,@RequestMapping都是再熟悉不过的了。如果搭过spring-mvc项目都知道,通常需要在web.xml文件中,配置一个ContextLoaderListener,contextConfigLocation,DispatcherServlet,可能很多人都是从网上copy了一份配置过来或者知道contextConfigLocation是指定spring配置文件的位置,DispatcherServlet是接收所有请求的前端控制器,需要指定拦截路由:“/”,从而拦截所有URL中带“/”的请求,但是在spring源码中是怎么使用这些组件的呢?以及怎么配置了一个@Controller,@RequestMapping中指定了一个url,就可以访问了呢?还有就是通常我们的web项目都会部署在web容器,如tomcat当中,那么tomcat和spring有啥关系呢?所以我们可以带着这些问题去查看spring源码找到答案。
  • 所以我推荐是从spring-mvc开始看spring源码,因为这个是我们使用得比较多,比较容易理解的一个模块,然后一层一层往上剥,找到与spring-context,spring-beans,spring-aop等的关系。如果真的对JavaWeb开发,Java EE很感兴趣,或者更容易读懂spring的源码,可以先看servlet规范和Tomcat的设计与Tomcat的请求处理工作流。我目前也在结合这两个方面看,也可以看下我的Tomcat源码分析系列。

二、Servlet规范

  • 在servlet的规范当中,servlet容器或者叫web容器,如tomcat,中运行的每个应用都由一个ServletContext表示,在web容器中可以包含多个ServletContext,即可以有多个web应用在web容器中运行。如在tomcat的webapp目录下,每个war包都对应一个web应用,tomcat启动时会解压war包,并启动相关的应用。
  • 在web容器启动的时候,会初始化web应用,即创建ServletContext对象,加载解析web.xml文件,获取该应用的Filters,Listener,Servlet等组件的配置并创建对象实例,作为ServletContext的属性,保存在ServletContext当中。之后web容器接收到客户端请求时,则会根据请求信息,匹配到处理这个请求的Servlet,同时在交给servlet处理之前,会先使用应用配置的Filters对这个请求先进行过滤,最后才交给servlet处理。
  • 了解web容器启动,之后接受客户端请求这些知识有啥用处呢?这里我们需要回过头来看我们的spring项目。我们在日常开发中,直接接触的是spring相关的组件,然后打成war包,放到web容器中,如拷贝到tomcat的webapp目录,并不会直接和web容器打交道。经过以上的分析,其实一个spring项目就是对应web容器里的一个ServletContext,所以在ServletContext对象的创建和初始化的时候,就需要一种机制来触发spring相关组件的创建和初始化,如包含@Controller和@RequestMapping注解的类和方法,这样才能处理请求。

三、Listener监听器机制:ContextLoaderListener

  • servlet规范当中,使用了Listener监听器机制来进行web容器相关组件的生命周期管理以及Event事件监听器来实现组件之间的交互。
  • 其中一个重要的生命周期监听器是ServletContextListener。web容器在创建和初始化ServletContext的时候,会产生一个ServletContextEvent事件,其中ServletContextEvent包含该ServletContext的引用。然后交给在web.xml中配置的,注册到这个ServletContext的监听器ServletContextListener。ServletContextListener在其contextInitialized方法中定义处理逻辑,接口定义如下:
    /** * Implementations of this interface receive notifications about changes to the * servlet context of the web application they are part of. To receive * notification events, the implementation class must be configured in the * deployment descriptor for the web application. * * @see ServletContextEvent * @since v 2.3 */
    public interface ServletContextListener extends EventListener { 
         
    
        /** ** Notification that the web application initialization process is starting. * All ServletContextListeners are notified of context initialization before * any filter or servlet in the web application is initialized. * @param sce Information about the ServletContext that was initialized */
        public void contextInitialized(ServletContextEvent sce);
    
        /** ** Notification that the servlet context is about to be shut down. All * servlets and filters have been destroy()ed before any * ServletContextListeners are notified of context destruction. * @param sce Information about the ServletContext that was destroyed */
        public void contextDestroyed(ServletContextEvent sce);
    }
    

    从contextInitialized的注释可知:通知所有的ServletContextListeners,当前的web应用正在启动,而且这些ServletContextListeners是在Filters和Servlets创建之前接收到通知的。所以在这个时候,web应用还不能接收请求,故可以在这里完成底层处理请求的组件的加载,这样等之后接收请求的Filters和Servlets创建时,则可以使用这些创建好的组件了。spring相关的bean就是这里所说的底层处理请求的组件,如数据库连接池,数据库事务管理器等。

  • ContextLoaderListener:spring-web包的ContextLoaderListener就是一个ServletContextListener的实现类。ContextLoaderListener主要用来获取spring项目的整体配置信息,并创建对应的WebApplicationContext来保存bean的信息,以及创建这些bean的对象实例。默认去WEB-INF下加载applicationContext.xml配置,如果applicationContext.xml放在其他位置,或者使用其他不同的名称,或者使用多个xml文件,则与指定contextConfigLocation。具体spring源码的实现过程后续文章详细分析。
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 修改配置文件路径 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/applicationContext.xml</param-value>
    </context-param>
    

四、DispatcherServlet:前端控制器

  • 在web容器中,web.xml中的加载顺序:context-param -> listener -> filter -> servlet。其中ContextLoaderListener是属于listener阶段。我们通常需要在项目的web.xml中配置一个DispatcherServlet,并配置拦截包含“/”路径的请求,即拦截所有请求。这样在web容器启动应用时,在servlet阶段会创建这个servlet,由Servlet规范中servlet的生命周期方法可知:
    public interface Servlet { 
         
        void init(ServletConfig var1) throws ServletException;
    
        ServletConfig getServletConfig();
    
        void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    
        String getServletInfo();
    
        void destroy();
    }
    

    web容器在创建这个servlet的时候,会调用其init方法,故可以在DispatcherServlet的init方法中定义初始化逻辑,核心实现了创建DispatcherServlet自身的一个WebApplicationContext,注意在spring中每个servlet可以包含一个独立的WebApplicationContext来维护自身的组件,而上面通过ContextLoaderListener创建的WebApplicationContext为共有的,通常也是最顶层,即root WebApplicationContext,servlet的WebApplicationContext可以通过setParent方法设值到自身的一个属性。DispatcherServlet默认是加载WEB-INF下面的“servletName”-servlet.xml,来获取配置信息的,也可以与ContextLoaderListener一样通过contextLoaderConfig来指定位置。DispatcherServlet具体的源码设计在之后文章详细分析。

五、总结

  • 从上面的分析,可知spring相关配置解析和组件创建其实是在web容器中,启动一个web应用的时候,即在其ServletContext组件创建的时候,首先解析web.xml获取该应用配置的listeners列表和servlet列表,然后保存在自身的一个属性中,然后通过分发生命周期事件ServletContextEvent给这些listeners,从而在listeners感知到应用在启动了,然后自定义自身的处理逻辑,如spring的ContextLoaderListener就是解析spring的配置文件并创建相关的bean,这样其实也是实现了一种代码的解耦;其次是创建配置的servlet列表,调用servlet的init方法,这样servlet可以自定义初始化逻辑,DispatcherServlet就是其中一个servlet。
  • 所以在ContextLoaderListener和DispatcherServlet的创建时,都会进行WebApplicationContext的创建,这里其实就是IOC容器的创建了,即会交给spring-context,spring-beans包相关的类进行处理了,故可以从这里作为一个入口,一层一层地剥spring的源码了。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/170004.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 光流法测距

    光流法测距一.基于特征点的目标跟踪的一般方法基于特征点的跟踪算法大致可以分为两个步骤:1)探测当前帧的特征点;2)通过当前帧和下一帧灰度比较,估计当前帧特征点在下一帧的位置;3)过滤位置不变的特征点,余下的点就是目标了。二.光流法1.首先是假设条件:(1)亮度恒定,就是同一点随着时间的变化,其亮度不会发生改变。这是基本光流法的假定(所有光流法变种都必须满足),用于得到光流法基本方程;(2)小运动,这…

  • WebSocket :用WebSocket实现推送你必须考虑的几个问题

    WebSocket :用WebSocket实现推送你必须考虑的几个问题目录:目录WebSocket简介项目背景硬件环境及客户端支持本文研究内容基于javaxwebsocket服务端代码源码后续补充git连接客户端代码问题探索如何做到支持几千个client同时在线人数后续1.WebSocket简介WebSocket_百度百科2.项目背景、硬件环境及客户端支持本项目通过WebSocket实现同时在线用户量5k推送服务器(可内网运行)。且可实时查看用户在线状

  • treeview属性方法_treewidget添加item

    treeview属性方法_treewidget添加itemTreeView控件属性属性说明AutoGenerateDataBindings可以设置为true。默认情况下需要手工设置数据和树接点的绑定关系CheckedNodes返回那些多选框被选中的节点的集合CollapseImageToolTip当节点处于折叠状态时,所显示

  • pycharm-2021.3.3激活码破解方法

    pycharm-2021.3.3激活码破解方法,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • 10个最好的 JavaScript 动画库【值得收藏】

    10个最好的 JavaScript 动画库【值得收藏】前端动画场景需求多众多,面对这么多花里胡哨的动画需求,这里给大家推荐10个比较好用的js动画库,轻松实现各种花里胡哨的动画❤️1.Tween.jsTweenJS是一个简单的JavaS…

    2022年10月15日
  • stream 流排序_把1列的数据倒序排列

    stream 流排序_把1列的数据倒序排列很多时候由于需求的复杂性,很多直接从数据库查出的数据并不能直接返回前端,需要进行处理,处理之后又需要排序,这时候一般都会使用Stream流的Sort排序场景一:普通排序正序(升序)list=list.stream().sorted().collect(Collectors.toList());或者list.stream().sorted(Comparator.comparing(Student::…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号