Demo搭建
springboot用多了很多东西都自动配置,其中的原理都不太了解,这次不用springboot用最基本的springmvcdemo来探寻springmvc其中的原理
根据官网提供的demo搭建了一个最简单的springMVCdemo。
SPI机制
这个demo的第一个问题是,为什么写了一个继承于WebApplicationInitializer的类就能被tomcat给自动加载到。那么我们就得先讲一下什么是SPI机制,要说SPI又得先说一个java的类ServiceLoader该类的作用是传入指定接口后回加载当前系统中所有实现类
身为实现类,想要被ServiceLoader加载到的方法是在META-INF/services中创建一个名字是接口全路径的文件,文件内容是自己实现类的全路径
SpringMVC中的SPI机制
在了解了SPI的原理之后,我们来看springMVC中的SPI应用
从图上我们可以看到springmvc实现了SPI让tomcat能加载到
SpringServletContainerInitializer类
然后根据JSR的另一个协议,传过来的全部都是指定好的类
而这个类就是我们自定义的类实现的类,所以我们自定义的类的方法才被执行。
SpringMVC启动流程
知道了springMVC是如何能被tomcat加载之后,我们来看springMVC的启动流程。
我们再来看一下我们写的springMVC初始化代码
public void onStartup(ServletContext servletContext) throws ServletException {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
我们创建了一个IOC容器,然后传递给了 DispatcherServlet 然后让tomcat加载了这个servlet。我们就先来研究这个servlet
从继承图可以看出这个servlet经过了tomcat和spring的封装。可以从servlet顶层的
生命周期开始看代码
当一个servlet被初始化的时候会调用该servlet的init方法,当调用方法的时候会调用service方法。
DispatcherServlet的init流程
老套的模板方法,一层一层继承下来,最后是在
FrameworkServlet类中执行了IOC容器的刷新方法。我们只需要关注 FrameworkServlet里面干的事情,重点来看一下 initWebApplicationContext方法
我们看到在方法中有给SpringMVC添加父容器的这么一个动作。我们很自然的想到了Spring的容器和SpringMVC容器整合的操作,SpringMVC只扫描controller的bean,然后Spring扫描service,dao的bean。整合的原理的就是这个父子容器。
SpringMVC的父子容器启动过程
在spring官网有这么一张图,表示了SpringMVC和Spring的关系
现在使用spring和springMVC整合的demo来看看是整合的原理是什么
使用一个新的继承类
AbstractAnnotationConfigDispatcherServletInitializer,我们研究这个类就可以了解springMVC整合spring的流程
首先还是从onStartUp方法开始,在父类
AbstractDispatcherServletInitializer中写了方法
可以看到首先调用了super的onStartUp,我们先看上面的流程
父类创建了一个IOC容器并且放到了一个监听器里面
创建IOC容器的配置也是交给我们自定义实现的配置类。看完父类的逻辑我们再来看看接下来的逻辑
可以看到父类创建了一个IOC容器和监听器之后,子类自己也创建了一个IOC容器并且放到了dispatcherServlet中。流程结束
tomcat启动过程中spring整合的过程
在onStartUp中创建了两个IOC容器,然后还有一个监听器就结束了,所以我们现在来看监听器的流程,他是如何把两个IOC容器整合并且执行refresh方法的
这是Spring创建的listener类图
在tomcat生命周期过程中会执行listener的方法,调用的是父类ContextLoader的init方法
随后tomcat初始化完成,执行dispatcherServlet的生命周期方法,把springIOC容器作为自己的父容器
SpringMVC想要获取父容器bean
在 AbstractBeanFactory中的getType方法中可以看到如果自己没有就找父类要的代码