一、先找到入口:
1、先说找发:
- 根据配置文件找
这个是最常见的搞法,在原始阶段大多数都会使用一些配置文件来启动这些框架,但是随着springboot类似的搞法的流行,这个技巧有点不在那么起作用,其实原理还是这个。 - 依据j2ee的规范来找:
首先我们要搞明白两个规范(也是本次会用到的):- web容器在启动初始化servlet时会调用其 init()方法,在接触请求处理时会调用service()方法,在销毁是会调用destory()方法
- web在启动时会调用一系列的监听器的方法,例如我们下面要说的这个
- 依据启动的配置:
这个其实有点多余,我们在看mybatis的时候其实就是这个高的,new SqlSessionFactoryBuilder().build(is); 其实我们要点进去看,会发现build就是其初始化的入口,初始化配置文件,解析mapper等等…… - 依据j2ee的注解规范来找:
现在大多框架为了简化配置,则使用了大量的注解,所以也可以通过这个来找,前提是你要对这些注解有了解
2、不多说来找找springmvc的入口
首先当然要看配置文件呀(当然现在也可以通过注解做到,这里便不在多做解释,因为spring环境要通过注解做还是挺费劲,大多数还是配置文件,这也是sb出现的原因) web.xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
我们看到配置了一个listener,大家可以看到还是实现的ServletContextListener,这个监听器是属于j2ee规范里面的,在web容器启动的时候会调用ServletContextListener的contextInitialized,那么这里面直接debug进去查看这个方法都干了什么initWebApplicationContext(),当然这一分支的体系过于庞大,所以本文的介绍重点还是说下面配置的一个servlet DispatcherServlet。
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {}
二、Springmvc:
我们来看一下,我们是如何一步演化到springmvc的程度的
1、springmvc没有出现的时候:
- 一个请求对应一个servlet
后来大家发现如果应用一旦打起来,这个目录结构太要命,相信很多初学者搞这个也是十分费劲,下面咱们进化一下。 - 使用一个servlet来做请求,然后做转发根据请求的名字和方法名字匹配来做转发调用
如:http://localhost:8080/cms/user/login
对应的代码
doPost(){
if ("login".equals(methodName)){
login();
}else if(){
}
}
看了这种搞法,是不是觉得很蠢,如果多一个请求就要去改这个类里面的方法,但是初期的确有人这么搞过,不幸的是笔者当年也这么干过
- 在进化,通过反射来进行单独处理:
http://localhost:8080/test/UserServlet?method=login
例如这个url,我们可以拿到处理类UserServlet,和要使用的方法login,
Method method UserServlet.class.getMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);
String result = (String)method.invoke(UserServlet.class.newInstance(), request,response);
然后在依据返回值来做重定向还是转发。差不多这个就是BaseServlet的原型了,这个上面是我在markdown手写的代码,只是一个简要的说明代码,之前写过的笔记招就不知道哪去了,所以这个地方放置一个网上写的不错的代码:
BaseServlet
2、springmvc重复的轮子:
springmvc的出现把这上面的代码多了许多层的封装使得能够处理更多的情况,例如:国际化,参数的格式化、参数的校验……
三、DispatcherServlet:
1.DispatcherServlet的初始化图
下面开始进去正题,DispatcherServlet的类图结构:关于ApplicationContextAware这一块的咱先不画,暂时也不研究,后面再逐一攻破
看到这个类图其实大家就应该在回忆回忆Servlet的类图了(回忆一下核心的知识点),有很多的方法我都没有标注,只是标注了一些比较核心的方法,在这里我写出一些常见的面试题大家回一下:
- servlet的生命周期
- jsp的九大隐式对象
- jsp的四大作用域
- servlet是单例的吗?是线程安全的吗?
- forwar和redirect的区别
- session和cookie的区别以及常见api
- 拦截器、监听器(种类、作用、应用场景)
下面我们通过一个时序图来画一下DispatcherServlet初始化所干的事儿(由于用的是老版的visio所以图画的有点烂,不过能看懂就好)写博客画图能力的确提升了不少。
我用红色标注的地方请大家注意,这个是ioc的初始化入口,spring最为基础核心的部分就是ioc,这个体系我也没有弄的太熟悉,所以等我把脑图整理好,然后在写一个系统化的博文出来。
上面的两幅图大概可以把DispatcherServlet的问题出明白,其实spring的东西以及体系是非常的大的,想要一篇博文把所有的东西出明白是不现实的,所以这一系列的博文会挑一些重点的来说。
2.其它可关注的点:
- spring的事件体系(这个体系到现在我没理清楚,所以只能见一个折腾一个),这个就是当springmvc收到refresh event的时候重新 执行onRefresh方法重新初始化springmvc的九大组件
- 在HttpServletBean中出现的BeanWrapper的作用,有兴趣可以多研究研究
大多出现Wrapper的都是和Bean的反射内省是相关的,Mybatis也是同样的套路
这个是目前整理的spring源码解析的相关的思维导图,以及java并发相关的思维导图,这个里面有大量的备注,体系太庞大所以截图难以截清楚,如果需要可以加入群,群是初建的所以没有什么人,希望大家可以成为朋友一起交流。后面也会把这些思维导图做一个输出写成博客来丰富和系统化自己的知识体系。下期博文:springmvc请求应答流程、springmvc九大组件的讲解。敬请期待!!!