标准MVC模型概述
MVC模型:是一种架构型的模式,本身不引入新功能,只是帮助我们将开发的结构组织的更加合理,使展示与模型分离、流程控制逻辑、业务逻辑调用与展示逻辑分离。如图1-1
首先让我们了解下MVC(Model-View-Controller)三元组的概念:
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据) 和 服务层(行为)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。 也就是说控制器做了个调度员的工作,。
从图1-1我们还看到,在标准的MVC中模型能主动推数据给视图进行更新(观察者设计模式,在模型上注册视图,当模型更新时自动更新视图),但在Web开发中模型是无法主动推给视图(无法主动更新用户界面),因为在Web开发是请求-响应模型。
那接下来我们看一下在Web里MVC是什么样子,我们称其为 Web MVC 来区别标准的MVC。
Web MVC概述
我们再看一下Web MVC标准架构,如图1-2
在Web MVC模式下,模型无法主动推数据给视图,如果用户想要视图更新,需要再发送一次请求(即请求-响应模型)。
和许多的 Web 框架一样,Spring MVC 是围绕着一个前端控制器模式进行设计的。这里围绕着一个 Servlet,它被称为 DispatcherServlet。这里提供了用于处理请求的的共享算法,而实际的工作是由配置的委托组件去执行的。这种模型非常灵活,并支持多种工作流程。
下面将从 Serlvet 注册、IoC 容器创建、Bean 初始化、MVC 的流程这几个方面进行阐述。
Serlvet 注册
Spring MVC 所依赖的 DispatcherServlet 和普通的 Servlet 一样,需要我们通过 Java 代码或者 web.xml文件进行配置。同时 DispatcherServlet 使用 Spring 的配置文件来发现它所需要进行处理程序映射、视图解析、异常处理等工作的委托组件。
web.xml 文件
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app/*</url-pattern>
</servlet-mapping>
</web-app>
有一个这里的小细节,上面的 XML 文件中出现了两个文件路径。
这里的 中的 是对整个 application 的上下文参数。这个是配置在 Web 下面的,Spring 框架在加载配置文件的时候,加载的是 配置文件的内容。
而 中的 是对 DispatcherServlet 的上下文参数,只有初始化了这个 Servlet,才会加载 中的配置文件。
IOC容器创建
IOC简介
IOC为控制反转(Inversion of Control)的缩写,是面向对象编程的一种设计原则,最常见的方式有依赖注入(DI)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
比如Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。
但是采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定。
Spring 中的 IoC 容器
Spring中提供了两种 IoC 容器: BeanFactory 和 ApplicationContext。
其中 ApplicationContext 是 BeanFactory 的子类,ApplicationContext 是基于 BeanFactory 构建的,功能更强大 。
在 Spring MVC 中,IoC 容器为 ApplicationContext 接口。它负责实例化并配置和装配需要托管的对象。容器通过读取配置文件或者代码获取托管对象的描述信息。
容器的创建也提供了两种方法:
Java代码:
对于 ApplicationContext 接口,Spring 提供了 ClassPathXmlApplicationContext 或 FileSystemXmlApplicationContext 的实现类来创建你的 IoC 容器。
ApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
WebApplicationContext
在 Spring 中,配置好了监听器,在启动时会创建一个 WebApplicationContext,Spring 初始化的过程中会调用 ContextLoader中的 initWebApplicationContext() 方法生成一个 WebApplicationContext。
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Bean 初始化
Bean简介
被称作 bean 的对象是构成应用程序的支柱也是由 Spring IOC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的。
Bean的配置项
属性
描述
Id
IOC容器中Bean的唯一标识
class
这个属性是强制性的,并且指定用来创建 bean 的 bean 类。
name
这个属性指定唯一的 bean 标识符。在基于 XML 的配置元数据中,你可以使用 ID 和/或 name 属性来指定 bean 标识符
scope
这个属性指定由特定的 bean 定义创建的对象的作用域,它将会在 bean 作用域的章节中进行讨论。
constructor-arg
构造器参数,它是用来注入依赖关系的。
properties
属性,它是用来注入依赖关系的。
autowiring mode
自动装配模式,它是用来注入依赖关系的。
lazy-initialization mode
懒加载模式,延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。
initialization 方法
在 bean 的所有必需的属性被容器设置之后,调用回调方法。它将会在 bean 的生命周期章节中进行讨论。
destruction 方法
当包含该 bean 的容器被销毁时,使用回调方法。它将会在 bean 的生命周期章节中进行讨论。
id和name的异同点:
•他们都是唯一的
•一个Bean只能有一个id,但可以有多个name。
Bean 的生命周期![在这里插入图片描述](https://img-blog.csdnimg.cn/20200415215317956.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMzI3NTI4,size_16,color_FFFFFF,t_70)
Bean的配置
基于XML配置
将其配置在applicationContext.xml中,由由标签表示。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.example.controller"/>
<context:component-scan base-package="org.example.jdbc"/>
<context:component-scan base-package="org.example.dao"/>
<bean id="Homework" name="Homework" class="org.example.dao.Homework" scope="prototype"/>
<bean id="Student" name="Student" class="org.example.dao.Student" scope="prototype"/>
<bean id="StudentHomework" name="StudentHomework" class="org.example.dao.StudentHomework" scope="prototype" />
<bean id="Teacher" name="Teacher" class="org.example.dao.Teacher" scope="prototype"/>
<bean id="HomeworkJdbc" name="HomeworkJdbc" class="org.example.jdbc.HomeworkJdbc" scope="prototype"/>
<bean id="Login" name="Login" class="org.example.jdbc.LoginJdbc" scope="prototype"/>
<bean id="StudentHomeworkJdbc" name="StudentHomeworkJdbc" class="org.example.jdbc.StudentHomeworkJdbc" scope="prototype"/>
<bean id="UserJdbc" name="UserJdbc" class="org.example.jdbc.UserJdbc" scope="prototype"/>
</beans>
基于注解的配置
首先Spring 能够从 classpath 下自动扫描(需要配置 context:component-scan )具有特定注解的组件。
<context:component-scan base-package="org.example.controller"/>
<context:component-scan base-package="org.example.jdbc"/>
<context:component-scan base-package="org.example.dao"/>
@Component("Homework")
public class Homework{
...
}
基于Java的配置
基于Java类定义Bean配置元数据,其实就是通过Java类定义Spring配置元数据,且直接消除XML配置文件。
使用@Configuration注解需要作为配置的类,表示该类将定义Bean的元数据
使用@Bean注解相应的方法,该方法名默认就是Bean的名称,该方法返回值就是Bean的对象。
AnnotationConfigApplicationContext或子类进行加载基于java类的配置
@Configuration
public class ApplicationContextConfig {
@Bean
public String login() {
return "hello";
}
}
MVC的流程
1.用户发送请求至前端控制器DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
2.DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3.处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4.DispatcherServlet调用HandlerAdapter处理器适配器。
5.HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6.Controller执行完成返回ModelAndView。
7.HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9.ViewReslover解析后返回具体View。
10.DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11.DispatcherServlet响应用户。