zoukankan      html  css  js  c++  java
  • 基于Servlet3.0的编程式SpringMVC实例详解

    传统的SpringMVC应用都是基于web.xml配置的,首先使用context listener启动Spring上下文,再配置一个DispatcherServlet启动一个WebApplicationContext子上下文,它可以获取Spring上下文的bean,同时也是Controller的容器。从Servlet3.0开始支持编程式配置,SpringMVC怎么支持的呢,本文通过一个实例详解这个过程。先建一个配置类:

    @Configuration
    @EnableWebMvc
    @ComponentScan("com.acwei.spring.mvc")
    public class MvcConfiguration {
    
    }

    这个类没有任何内容,和一般的配置类不同之处是多了@EnableWebMvc注解。我们通过源码查找它做了哪个工作

    我们看到,它导入了DelegatingWebMvcConfiguration配置类,而DelegatingWebMvcConfiguration类又继承了WebMvcConfigurationSupport,这两个类做了大量的默认配置工作,包括注册HandlerMapping,注册Interceptor,设置内容协商,MessageConverter等默认配置。这个配置类的作用就相当于传统的spring mvc xml配置文件。

    Spring还给我们提供了 一个类WebMvcConfigurerAdapter,可能通过扩展这个类实现Spring MVC其他配置,例如增加一个日志拦截器:

    @Configuration
    @EnableWebMvc
    @ComponentScan("com.acwei.spring.mvc")
    public class MvcConfiguration extends WebMvcConfigurerAdapter {
        
        @Bean
        public LogInterceptor logInterceptor() {
            return new LogInterceptor();
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(logInterceptor()).addPathPatterns("/**");
        }
    }
    public class LogInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("access " + request.getRequestURI());
            return true;
        }
    
    }

    其他Spring MVC配置详见源码。

    最后一步,初始化Spring上下文,并注册一个Dispatcher Servlet:

    public class MvcInitializer implements WebApplicationInitializer {
    
        public void onStartup(ServletContext servletContext) throws ServletException {
            // 创建WebApplication上下文
            AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
            // WebApplication上下文需要设置ServletContext
            context.setServletContext(servletContext);
            // 注册一个配置类
            context.register(MvcConfiguration.class);
    
            Dynamic servlet =
                    servletContext.addServlet("dispatcher", new DispatcherServlet(context));
            servlet.addMapping("/");
            servlet.setLoadOnStartup(1);
        }
    
    }

    这个类很关键,它替代了传统的web.xml配置文件。我们先是手动创建了SpringContext,替代了context listener的方式。注意,这里只有一个上下文,也就没有传统的父子上下文概念了。然后将上面的MvcConfiguration注册到上下文。最后向ServletContext注册了与SpringContext关联的DispatcherServlet。所有步骤已经完成,我们创建一个Controller测试一下:

    @RestController
    public class HelloController {
    
        @GetMapping("/hello")
        @ResponseBody
        public String hello() {
            return "hello world";
        }
    
    }

    deploy到Tomcat启动,访问http://localhost:8080/mvc/hello

    响应正常

    拦截器也正常。我们已经按照Servlet3.0的无xml方式搞定了Spring MVC。但还有一个很关键的点,ServletContext怎么来的?我们看WebApplicationInitializer这个接口,它的注释是:Interface to be implemented in Servlet 3.0+ environments in order to configure the ServletContext programmatically。也就是说这个接口就是为Servlet3.0编程式配置的方式准备的。这个接口在org.springframework.web.SpringServletContainerInitializer被用到了

    再看ServletContainerInitializer接口,这是一个servlet的接口

    在这里看到了ServletContext来源了,在Servlet容器启动时候,会将jar包中META-INF/services/javax.servlet.ServletContainerInitializer文件注册的实现了ServletContainerInitializer接口的类实例化,并调用其onStartup方法将ServletContext对象传给它。Spring对应的实现类是SpringServletContainerInitializer,同时加了注解@HandlesTypes(WebApplicationInitializer.class),所以Servlet容器将所有WebApplicationInitializer实现类作为参数c传给它。我们再看下Spring在onStartup方法做了啥:

    在最后执行了WebApplicationInitializer接口的onStartup方法,那么我自定义的实现MvcInitializer也就被执行了。

    以上是Spring MVC对Servlet3.0+编程式配置支持分析,关键点是Servlet Api提供了ServletContainerInitializer接口,在启动容器时调用onStartup方法将ServletContext对象传给应用程序,Spring在拿到ServletContext对象后又调用了初始化接口,我们才能注册Servlet,创建SpringContext。

  • 相关阅读:
    bzoj3033: 太鼓达人
    CH Round #24
    王志明:编辑部不送审,把你的投稿直接拒掉了,怎么办?
    用TinyXml做XML解析示例 TinyXml查找唯一节点及修改节点操作
    QT XML文档的解析 QXmlStreamReader, DOM,SAX 三种解析方法 简单示例
    QT 使用QUdpSocket QUdpServer UDP 建立客户端与服务器端
    QT 使用QTcpServer QTcpSocket 建立TCP服务器端 和 客户端
    Qt QThread 线程创建,线程同步,线程通信 实例
    Qt QT的IO流 QT输入输出
    Qt QSortFilterProxyModel示例代码, 使用方法
  • 原文地址:https://www.cnblogs.com/c04s31602/p/11221280.html
Copyright © 2011-2022 走看看