• Spring MVC AbstractAnnotationConfigDispatcherServletInitializer


    Spring MVC AbstractAnnotationConfigDispatcherServletInitializer 用于 DispatcherServlet 初始化

    DispatcherServlet 是 Spring MVC 的核心组件,它是一个 request 首先到达的地方,负责 request 在其他各个组件间的传递加工,在过去,像 DispatcherServlet 这样的 servlets 是使用 web.xml 文件配置的。

    基于 Servlet 3 和 Spring 3.1 的一些新特性,我们可以用更简单的方式来配置,即使用 Java 代码。

    简单来说,AbstractAnnotationConfigDispatcherServletInitializer 自动被加载,负责应用程序中 servlet 上下文中的 DispatcherServlet 和 Spring 其他上下文的配置。

    Spring MVC提供基类 AbstractAnnotationConfigDispatcherServletInitializer,用于 DispatcherServlet 初始化(实现了WebApplicationInitializer接口),该基类既要完成 WebApplicationInitializer 接口中配置servlet容器的功能,又完成了配置MVC的功能,即同时配置了 DispatcherServlet 和 ContextLoaderListener 。

    package com.it.config;
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
    
    public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
        /*
        加载 Spring 配置类中的信息,
        初始化 Spring 容器
       */
        protected Class<?>[] getRootConfigClasses() {  //配置root上下文,如Jpa数据源等等的配置
    return new Class[]{SpringConfig.class}; }
    /* 加载 Spring MVC 配置类中的信息, 初始化 Spring MVC 容器 */ protected Class<?>[] getServletConfigClasses() {//配置dispatcher servlet,如果在root config指定了该转发规则就可以忽略

    return new Class[]{SpringMvcConfig.class}; }
    //配置 DispatcherServlet 的映射路径 //指定开始被 servlet 处理的url,配置从 / 开始
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    }

    getServletMappings() 的进一步说明:

    通常情况下,大家配置spring mvc的路径拦截(ServletMapping)都习惯配置“/”,但在某些特殊场景下,你可能希望所有的mvc的路径都有个固定的前缀,形如“/springmvc/*”,如果你在springmvc的ServletMapping中配置了这种路径,那么你的URL访问地址和controller的path就要注意了:如果你的地址栏URL为"/springmvc/user",那么你的controller中的path就必须配置"/user",因为spring mvc拦截了所有以“/springmvc”为前缀的请求,而在匹配的时候也截掉了“/springmvc”,用剩下的“/user”匹配controller。
    如果路径设置为“/”,则所有的请求都会由DispatcherServlet处理。

    如何取代传统的 web.xml 搭建Spring MVC,DispatcherServlet 是 Spring MVC 的核心,我们都会把它放在 web.xml 文件中,但是自从有了 Servlet 3 规范和 Spring 3.1 的功能增强,这种方式就不是唯一的方案了.

    一、AbstractAnnotationConfigDispatcherServletInitializer

    要想替代 web.xml 中的 DispatcherServlet,我们就需要扩展 AbstractAnnotationConfigDispatcherServletInitializer,任意的类扩展它后,都会自动的配置 DispatcherServlet 和 Spring 应用上下文。

    注:在Spring 3.0环境中,容器会在类路径中查找实现 javax.servlet.ServletContainerInitializer 接口的类,如果能发现的话,就会用它来配置 Servlet 容器。Spring提供了这个接口的实现,名为 SpringServletContainerInitializer。这个类反过来会查找实现 WebApplicationInitializer 的类并将配置的任务交给它们来完成。

    Spring 3.2 引入了一个便利的WebApplicationInitializer基础实现,也就是 AbstractAnnotationConfigDispatcherServletInitializer ,如下面的图片,DispatcherServlet 实现了 AbstractAnnotationConfigDispatcherServletInitializer,因此当部署到Servlet 3.0容器中的时候,容器会自动发现它,并用它来配置Servlet上下文。

    类中有3个主要方法,getServletMappings, getRootConfigClasses, getServletConfigClasses。

    getServletConfigClasses 用来加载配置文件或配置类中所声明的bean。

    getRootConfigClasses 用来加载ContextLoaderListener要加载的bean。

    getServletMappings 用来定义请求URL

    二、WebMvcConfigurerAdapter

    要想实现视图解析、我们还需要扩展WebMvcConfigurerAdapter,使用@EnableWebMvc启用Spring MVC组件。

    viewResolver用来配置JSP视图解析器。

    configureDefaultServletHandling配置静态资源的处理.

    通过配置configureDefaultServletHandling的enable方法,我们要求DispatcherServlet将对静态资源的请求转发到Servlet容器中默认的Servlet上,而不是使用DispatcherServlet本身处理请求。

    三、Controller

    这个大家都熟悉也不用细说了。

     

    最后奉上整个项目截图

    示例:

    package org.springframework.source.config;
     
    import org.springframework.web.filter.CharacterEncodingFilter;
    import org.springframework.web.filter.DelegatingFilterProxy;
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
     
    import javax.servlet.*;
     
    public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
     
    //指定开始被servlet处理的url,配置从/开始
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
        
    //配置root上下文,如Jpa数据源等等的配置
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class<?>[] {ApplicationConfig.class, JpaConfig.class, SecurityConfig.class};
        }
        
    //配置dispatcher servlet,如果在root config指定了该转发规则就可以忽略
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class<?>[] {WebMvcConfig.class};
        }
    //配置servlet过滤器
        @Override
        protected Filter[] getServletFilters() {
            CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
            characterEncodingFilter.setEncoding("UTF-8");
            characterEncodingFilter.setForceEncoding(true);
            DelegatingFilterProxy securityFilterChain = new DelegatingFilterProxy("springSecurityFilterChain");
            return new Filter[] {characterEncodingFilter, securityFilterChain};
        }
    //当registerDispatcherServlet完成时自定义registration
        @Override
        protected void customizeRegistration(ServletRegistration.Dynamic registration) {
            registration.setInitParameter("defaultHtmlEscape", "true");
            registration.setInitParameter("spring.profiles.active", "default");
        }
    }

    =======================================================

    AbstractAnnotationConfigDispatcherServletInitializer 剖析

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

    Spring提供了这个接口的实现,名为 SpringServletContainerInitializer,这个类反过来又会查找实现 WebApplicationInitializer 的类并将配置的任务交给它们来完成。Spring 3.2 引入了一个便利的 WebApplicationInitializer 基础实现,也就是 AbstractAnnotationConfigDispatcherServletInitializer。因为我们的
    MyWebAppInitializer 扩展了 AbstractAnnotationConfigDispatcherServletInitializer,当然也就实现了 WebApplicationInitializer,因此当部署到Servlet 3.0 容器中的时候,容器会自动发现它,并用它来配置 Servlet上下文。

    尽管它的名字很长,但是 AbstractAnnotationConfigDispatcherServletInitializer 使用起来很简便。它仅要求我们重写其中的三个方法,其他的方法是否重写则根据你的具体需求而定。

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

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

    两个应用上下文之间的故事:

    当 DispatcherServlet 启动的时候,它会创建 Spring应用上下文,并加载配置文件或配置类中所声明的bean。在 MyWebAppInitializer 的 getServletConfigClasses() 方法中,我们要求 DispatcherServlet 加载应用上下文时,使用定义在 WebConfig配置类(使用Java配置)中的bean。但是在Spring Web 应用中,通常还会有另外一个应用上下文。另外的这个应用上下文是由 ContextLoaderListener 创建的。

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

    实际上,AbstractAnnotationConfigDispatcherServletInitializer 会同时创建 DispatcherServlet 和 ContextLoaderListener。getServletConfigClasses() 方法返回的带有@Configuration注解的类将会用来定义 DispatcherServlet 应用上下文中的bean,我们暂且把它记为context1。getRootConfigClasses()方法返回的带有@Configuration注解的类将会用来配置 ContextLoaderListener 创建的应用上下文中的bean,记为context2。那这两个上下文的关系是什么呢?答案是,context1会把context2设置为parent,这样,当context1中的bean需要使用到context2中的bean时就可以在其中直接获取,比如当我们把一个service层的bean注入到controller中时。

    在本例中,根配置定义在RootConfig中,DispatcherServlet 的配置声明在WebConfig中。稍后我们将会看到这两个类的内容。

    需要注意的是,通过 AbstractAnnotationConfigDispatcherServletInitializer 来配置 DispatcherServlet 是传统web.xml方式的替代方案。如果你愿意的话,可以同时包含 web.xml和 AbstractAnnotationConfigDispatcherServletInitializer,但这其实并没有必要。

    如果按照这种方式配置 DispatcherServlet,而不是使用web.xml的话,那唯一问题在于它只能部署到支持 Servlet 3.0的服务器中才能正常工作,如 Tomcat 7或更高版本。如果你还没有使用支持 Servlet 3.0的服务器,那么在 AbstractAnnotationConfigDispatcherServletInitializer 子类中配置 DispatcherServlet 的方法就不适合你了。你别无选择,只能使用web.xml了。
    -----------------------------------
    https://blog.51cto.com/u_9587581/2398187

    =======================================================


    REF

    https://blog.51cto.com/u_9587581/2398187

    https://baijiahao.baidu.com/s?id=1633224433148237378&wfr=spider&for=pc

    https://blog.csdn.net/renchenglin118/article/details/93207031

    https://blog.csdn.net/u013571243/article/details/44565289

    https://blog.csdn.net/classicer/article/details/50753019

  • 相关阅读:
    时钟同步
    通过 profiling 定位 golang 性能问题
    览器全面禁用三方 Cookie 全栈前端精选 4月16日
    为什么Go自带的日志默认输出到os.Stderr?
    gRPC Motivation and Design Principles | gRPC https://grpc.io/blog/principles/
    应用安全开发指南
    Hash Join: Basic Steps
    Building a high performance JSON parser
    阿姆达尔定律 Amdahl's law
    贝壳找房小程序平台架构演进
  • 原文地址:https://www.cnblogs.com/emanlee/p/15734426.html
Copyright © 2020-2023  润新知