spring mvc架构及最简单的应用
标签(空格分隔): springmvc springboot RestController RequestMapping EnableAutoConfiguration
最简单的例子
理论结合实践才能理解的更透彻,对于程序员来说,代码就是最好的实践,所以把代码例子放在开头。
例子主要参考SPRING BOOT : HELLO WORLD WITH MAVEN - 2018,是一个简单到不能再简单的例子。
ps:这里用的其实是spring boot的例子。spring boot和spring mvc的区别可以参考What is difference between spring MVC and spring boot?简单(不一定准确)来说spring boot的核心就是spring mvc,spring boot在spring mvc的核心上添加了自动配置的功能,简化了spring mvc的使用。
文本编辑器新建一个pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
修改groupId和artifactId(如果不修改,直接导入到IDE,项目的名字就叫做myproject,很难看),然后import到IDE中(我用的是Eclipse)。
新建一个个java文件
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
public class Example {
@RequestMapping("/")
String home() {
return "Hello World!";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Example.class, args);
}
}
架构
架构图
这个图来源于Overview of Spring MVC Architecture,图中把需要用户自己实现的部分用紫色的方框表现出来,理论和实践结合起来,所以让人觉得特别的清晰。
文章中还对架构图中的每一个部分基于一个请求的流程做了描述,如下:
1. DispatcherServlet receives the request.
2. DispatcherServlet dispatches the task of selecting an appropriate controller to HandlerMapping. HandlerMapping selects the controller which is mapped to the incoming request URL and returns the (selected Handler) and Controller to DispatcherServlet.
3. DispatcherServlet dispatches the task of executing of business logic of Controller to HandlerAdapter.
4. HandlerAdapter calls the business logic process of Controller.
5. Controller executes the business logic, sets the processing result in Model and returns the logical name of view to HandlerAdapter.
6. DispatcherServlet dispatches the task of resolving the View corresponding to the View name to ViewResolver. ViewResolver returns the View mapped to View name.
7. DispatcherServlet dispatches the rendering process to returned View.
8. View renders Model data and returns the response.
图是好图,文字说明好像也还可以,但是我总还是觉得不够清晰,然后再参考了下面两个图
以及
[站外图片上传中...(image-b66d03-1535359398625)]
综合起来理解应该就已经比较清晰。(这个也我在老程序员的一点套路之方法论中提到过的,看不明白的时候就多看几个人的描述)。
理论联系实际,从例子的角度说一下架构
HandlerMapping负责根据请求返回处理该请求的controller,结合例子,对于http://localhost:8080/这个请求,HandlerMapping会选中Example这个controller来进行处理。
HandlerAdapter负责调用controller中的具体的函数,结合例子,对于http://localhost:8080/这个请求,HandlerAdapter会调用home函数。
代码中的两个注解@RestController和 @RequestMapping("/")在上述的两个过程中起到了关键的作用,有他们的存在,HandlerMapping才能找到正确的controller,HandlerAdapter才能调用正确的函数去处理 http://localhost:8080/ 这个请求。so far,请求已经被处理,现在进入到返回处理结果的阶段。代码中的@RestController注解在这个阶段起了关键的作用,@RestController实际上是等价于 @Controller and @ResponseBody的组合
@Controller
@ResponseBody
其中@Controller表明Example是一个controller,HandlerMapping在找controller的时候就会考虑是不是要选Example(实际上Controller本质也是一个Bean,只是在Bean的基础上加了点东西以便HandlerMapping能区分是普通的Bean还是一个Controller);@ResponseBody则是指示框架跳过 view 相关的东西,直接把home的返回值作为http response的body。
这里详细说一下view。所谓的view简单来说,就是给html里面的变量赋值(这个动作有些文章会描述成渲染)的功能模块(这个模块有很多种实现,Thymeleaf就是其中的一种实现。也正因为有很多的实现,所以需要一个View Resolvers就是用来选view的,举个简单的例子,jsp页面就需要选jsp对应的view来处理),变量和变量值是controller的函数返回到 model里面的,,view根据model的内容修改html,完成后把它作为http response 的body返回。经过这样的说明,应该能理解为什么说本文中例子是不经过框架的view相关的处理的了吧。
其它
仔细点看就会发现,到目前为止,例子中还有点东西没交代。这是因为剩下的这点东西和spring mvc已经没有什么关系了,它们是纯粹属于spring boot在配置方面起作用的东西,包括@EnableAutoConfiguration和SpringApplication.run(Example.class, args),下面简单讲一下.
@EnableAutoConfiguration会扫描classpath下面的jar对他们进行自动的配置,这也是我理解的spring boot之所以很方面的一个最重要的原因。
至于SpringApplication.run(Example.class, args),值得一提的是第一个参数Example.class。为什么要用Example.class作为参数?让我们把@EnableAutoConfiguration改成@SpringBootApplication,或者会更好理解一些,@SpringBootApplication等价于@Configuration, @EnableAutoConfiguration 和 @ComponentScan的组合
@Configuration
@EnableAutoConfiguration
@ComponentScan
这三个东西里面只要关心@Configuration,就能解决第一个参数是Example.class的问题。如果简单的把@Configuration看成是一个xml,那么使用Example.class作为SpringApplication.run的参数,本质上相当于为程序指定了一个xml配置。
尾声
上面好像把一个简单的例子搞得不简单了,但是如果按照结合框架原理来领会最简单的例子这种路线来学习,一旦最简单的例子领悟了,那么整个框架用起来也已经不会有什么太大的问题了,至于碰到具体的需求,直接stackoverflow.com,在绝大多数情况下都能知道应该怎么做了。
所以对于搞应用开发而不是搞底层引擎的程序员来说,花点时间找找资料理解一下自己要用的东西的架构原理,对于使用来说也是很有好处的,学习成本并不高,很值得去做的。反正我是觉得挺管用的。
本文使用我另外的文章 老程序员的一点套路之开源学习 里面介绍的方法进行学习