SpringMVC


一、跟踪Spring MVC请求

springmvc

  1. 请求的第一站是SpringDispatcherServletDispatcherServlet查询一个或多个处理器映射(Handler Mappering),处理映射器会根据请求携带的URL信息来决策请求哪个控制器。
  2. 一旦选择了合适的控制器,DispatcherServlet会将请求发送给选中的控制器。到了控制器,请求会卸载其负载(用户提交的信息)并等待控制器处理这些信息。
  3. 控制器在完成逻辑处理后,通常会产生一些模型数据。控制器将这些模型数据打包,并且标记出用于渲染输出的视图名。接下来将请求连同模型和视图名发送回DispatcherServlet
  4. DispatcherServlet使用视图解析器(View Resolver)将逻辑视图名匹配为一个特定的视图实现。
  5. DispatcherServlet交付模型数据,视图使用模型数据渲染输出,这个输出会通过响应对象传递给客户端。

二、搭建Spring MVC

DispatcherServletSpirng MVC的核心,在这里请求会第一次接触到框架,它要负责将请求路由到其他组件之中。

按照传统的方式,像DispatcherServlet这样的Servlet会配置在web.xml中。这个文件会放到应用的war包中。当然这是配置DispatcherServlet方法之一。借助于Servlet 3规范Spring 3.1 的功能增强,这种方式已经不是唯一的方案。

使用Java将DispatcherServlet配置在Servlet容器中,而不是使用web.xml文件。

配置DispatcherServlet

public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected String[] getServletMappings() {   
        // 将DispatcherServlet映射到"/"
        return new String[]{"/"};
    }

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?> [] {RootConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        // 指定配置类
        return new Class<?> [] { WebConfig.class};
    }
}

我们只需要知道扩展AbstractAnnotationConfigDispatcherServletInitializer的任意类都会自动的配置DispatcherservletSpring应用上下文,Spirng的应用上下文会位于应用程序的Servlet上下文之中。

Servlet3.0环境中,容器会在类路径中 查找实现javax.servlet.ServletContainerInitialzer接口的类,如果能发现的话,就会用它来配置Servlet容器。

Spring提供了这个接口的实现名为SpringServletContainnerInitialzer,这个类反过来又会查找实现WebApplicationInitialzer的类,并将配置的任务交给他们来完成。Spring 3.2引入了一个便利的WebApplicationInitialzer基础实现也就是AbstractAnnotationConfigDispatcherServletInitializer因为我们的SpittrWebApplicationInitialzer扩展了AbstractAnnotationConfigDispatcherServletInitializer,(同时也就实现了WebApplicationInitialzer),因此当部署Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。

第一个方法getServletMappings(),它会将一个或多个路径映射到DispatcherServlet上,在本示例中,它映射的是”/“,表示它是应用默认的Servlet,它会处理应用的所有请求。

为了理解其他两个方法,我们首先需要理解DispatcherServlet和一个Servlet监听器(也就是ContextLoaderListener)的关系。

DispatcherServlet启动的时候,它会创建应用上下文,并加载配置文件或配置类中声明的bean。在上面那个程序中的getServletConfigClasses()方法中,我们要求DispatcherServlet加载应用上下文时,使用定义在WebConfig配置类(使用Java配置)中的bean。

但在Spring Web应用中,通常还会有另外一个应用上下文。另外这个就是由ContextLoaderListener创建。

我们希望DispatcherServlet加载包含Web组件的bean,如控制器,视图解析器,以及处理器映射。而ContextLoaderListener要加载应用中的其他bean,这些bean通常是驱动应用后端的中间层和数据层组件。

实际上AbstractAnnotationConfigDispatcherServletInitializer会同时创建DispatcherServletContextLoaderListenergetServletConfigClasses()方法会返回带有@Configuration注解的类将会用来定义DispatcherServlet应用上下文中的bean,getRootConfigClasses()会返回带有@Configuration注解的类将会用来配置ContextLoaderListener创建的应用上下文。

启用Spring MVC

我们有多种方式来启动DispatcherServlet,与之类似,启用Spring MVC组件的方式也不止一种,以前Spring是XMl进行配置的,你可以选择<mvc:annotation-driver>启用注解驱动的Spring MVC

我们所能创建最简单的Spring MVC配置就是一个带有@EnableWebMvc注解的类。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
public class WebConfig {
}

这可以运行起来,它的确能够启用Spring MVC,但还有不少问题要解决。

  • 没有配置视图解析器,如果这样的话,Spring默认会使用BeanNameView-Resolver,这个视图解析器会查找ID与视图名称匹配的bean,并且查找的bean要实现View接口,它以这样的方式来解析视图。

  • 没有启用组件扫描。这样的结果就是,Spring只能找到显示声明在配置类中的控制器。

  • 这样配置的话,DispatcherServlet会映射为默认的Servlet,所以他会处理所有的请求,包括对静态资源的请求,如图片 和样式表(在大多数情况下,这可能并不是你想要的结果)。

因此我们需要在WebConfig这个最小的Spring MVC配置上再加一些内容,从而让他变得真正实用。

@Configuration
@EnableWebMvc                           //启用Spring MVC
@ComponentScan("com.ql.controller")     //启用组件扫描
public class WebConfig extends WebMvcConfigurerAdapter {
    @Bean
    public ViewResolver viewResolver () {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        //配置JSP视图解析器
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        resolver.setExposeContextBeansAsAttributes(true);
        return resolver;
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        //配置静态资源的处理
        configurer.enable();
    }
}

WebConfig现在添加了@ComponentScan注解,此时将会扫描com.ql.controller包来查找组件。带有@Controller注解控制器将会成为组件扫描时的候选bean。因此,我们不需要在配置类中显示声明任何的控制器。

添加了一个ViewResolver bean,更具体的将是InternalResourceViewResolver。我们只需要知道他会去查找jsp文件,在查找的时候,它会在视图名称上加一个特定的前缀和后缀。(例如:名为home的视图会被解析为/WEB-INF/views/home.jsp)

WebConfig类还扩展里WebMvcConfigurerAdapter并重写了其configureDefaultServletHandling()方法,通过调用DefaultServletHandlerConfigurerenable()方法,我们要求DispatcherServlet将静态资源的请求转发到Servlet容器中默认的Servlet上,而不是使用DispatcherServlet本来来处理此类请求。

Web相关的配置通过DisPatcherServlet创建的应用上下文都已经配好了,接下来配置RootConfig

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@ComponentScan(basePackages = {"com.ql"},
    excludeFilters = {
        @Filter(type = FilterType.ANNOTATION,value = EnableWebMvc.class)})
public class RootConfig {

}

RootConfig使用了@ComponentScan注解,这样的话,我们就有很多机会用非Web的组件来完善RootConfig


以上


文章作者: Qliang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Qliang !
评论
 上一篇
深入理解Java虚拟机(2)之一-macOS下编译openjdk10 深入理解Java虚拟机(2)之一-macOS下编译openjdk10
==因为电脑系统版本和软件版本都比较高,在编译jdk7和jdk8的时候出现各种各样的问题,编译jdk10一次就ok了。== 编译openjdk10编译环境 系统环境 :macOS Mojave 10.14.3 编译器 :clang op
2019-06-10
下一篇 
bean的作用域 bean的作用域
Spring作用域定义默认情况下,Spring应用上下文中的bean都是以单例(singleton)的形式创建的。 Spring定义了多种作用域,可以基于这些作用域创建bean: 单例(Singleton):在整个应用中,只创建bean一
2019-03-26
  目录