SpringMvc映射原理以及SpringBoot的启动原理
我们使用SpringBoot最直观的感受就是springboot的自动装配,感觉什么都不用自己去做,只是去使用一些注解就可以完成各个层次之间的联系以及对象的注入,但有时候我们却不了解或者容易忘记为什么加了这些注解就可以达到这种效果,或者说,是否有一些疑惑,我们为什么要这么做,为什么这么做他就可以达到这种效果?
SpringMvc
我们不妨先从springmvc开始梳理,也会便于后期springboot的理解。
MVC主要作用是降低了视图与业务逻辑间的双向偶合。
最初的jsp+servlet
我们在最初写javaweb项目的时候,最开始的版本jsp+servlet.我们的操作往往是:
-
用户发请求
-
Servlet接收请求数据,并调用对应的业务逻辑方法
-
业务处理完毕,返回更新后的数据给servlet
-
servlet转向到JSP,由JSP来渲染页面
-
响应给前端更新后的页面。
具体到代码实现就是:
编写一个Servlet类,用来处理用户的请求,再写一个jsp页面,再去手动写web.xml将这两者进行绑定在web.xml中注册Servlet。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.zzm.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/user</url-pattern>
</servlet-mapping>
</web-app>
如果你经历了这方面的洗礼,可能会更好地加深前后端不分离的这种开发,加强一些对jsp,js知识以及前后端交互ajax的理解,本人最开始写的javaweb项目就是用jsp写的,可谓是相当地痛苦。
MVC框架
帮助我们:
将url映射到java类或java类的方法 ,封装用户提交的数据 .处理请求,调用相关的业务处理--封装响应数据 .将响应的数据进行渲染 . jsp / html 等表示层数据 。
我们在使用该框架的时候已经不需要去配置一些web.xml文件了,只需要一些注解就可以完成这类的映射关系,一下觉得,哇,轻松了好多。那么我们不妨去想想,它为什么会如此轻松,原理又是如何做到的?
这里有一个核心的类:DispatcherServlet
DispatcherServlet
本人在进行原理方面学习的时候,遇到了一位很忠爱的博主,可能在实际应用和扩展企业级知识的方面可能不够,但在某些学习的原理初探的地方讲的倒是津津有味:”狂神”。这位老师也让我深深地喜欢上去探索原理:
这里借用狂神的图:
dispatcherservlet:类的一些继承关系,这里还是建议大家去ctrl+左键去一层一层的看一下。
SpringMVC的原理图:
当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。
执行类图:
HandlerMapping:
HandlerMapping查找控制器:DispatcherServlet将HTTP请求交给HandlerMapping进行处理,HandlerMapping负责将请求映射到相应的控制器。HandlerMapping根据请求的URL和配置文件中的控制器映射信息,确定要调用的控制器对象
而这些类执行的流程如下:
-
DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
我们假设请求的url为 : http://localhost:8080/SpringMVC/hello
如上url拆分成三部分:
http://localhost:8080服务器域名
SpringMVC部署在服务器上的web站点
hello表示控制器
控制器实例理解:
@Controller
public class HelloController {
@RequestMapping("/hello")
public ModelAndView hello() {
ModelAndView modelAndView = new ModelAndView("hello");
modelAndView.addObject("message", "Hello, SpringMVC!");
return modelAndView;
}
}
在上面的示例中,控制器接收一个HTTP请求,并返回一个ModelAndView对象,其中包含了一个名为“message”的模型数据和一个名为“hello”的视图信息。
-
通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。
-
HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。
-
HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。
-
HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。
-
HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
-
Handler让具体的Controller执行。
-
Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。
-
HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。
-
DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。
-
视图解析器将解析的逻辑视图名传给DispatcherServlet。
-
DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。
-
最终视图呈现给用户。
以上就是SpringMVC中核心控制器DispatcherServlet的运行原理理解。当然,原理理解要取其精华弃其糟粕,结合出自己的理解才会更加深刻。
SpringBoot
在Spring里有很重要的概念,依赖注入和控制反转。这两个重要名词的官方概念spring官网都会有解释,我来说说我完全个人的理解,请大家结合自己的想法来理解,依赖注入就是将容器内的对象,在我们需要的时候进行取用,控制反转就是将创建某种对象的权限交给spring容器而不是我们自己,很直观的感受就是我们不用再去new,而是spring容器帮我们创建。
这种思想也更贴合springboot的自动装配
容器和上下文的概念:
我们在学习和利用SpringBoot的注解的时候,常常会涉及到这样的名字,有时候虽然我们能让程序正常运行,但我们往往不知道为什么要这样做,常常使用注解的时候带着疑惑,那我们不妨将他们弄清,或者能自己给出符合自己的理解,那下面则是我的理解:
所谓容器的概念就像是一个百宝箱,但这个箱子一开始并不是拥有你想要的所有东西,有些是已经配置好的,但很多需要用到的需要我们自己去放进去。那我们通过什么放进去?对,就是我们经常用到的注解,configuration,bean,component注解等等。他会让我们写的类和方法等变成bean对象放入spring的容器,那么容器内的东西就会被spring接管,它来分析你是在启动的时候还是应用的时候将这些bean对象自动的进行装配和应用。当你在程序创建对象也好,Exception处理也好,mybatisplus配置类也好,你想让这些类自动生效,那么就需要将这些东西给到spring容器,将控制权给他,让spring自动注入生效。而我们常见的上下文也就是我们放进容器的bean对象(我们写的类和方法)。我们常见的ApplicationContext本质上说就是一个维护Bean定义以及对象之间协作关系的高级接口。
通过以上的解释,我们是否对springboot中的configuration,bean,component等注解有了更深刻的理解,是否有种轻松的感觉?
SpringApplication启动类:
下面再结合狂神老师对spring启动类的运行过程的启动图: