首页 > 编程语言 >[Java/Spring] 深入理解:Spring Web DispatcherServlet

[Java/Spring] 深入理解:Spring Web DispatcherServlet

时间:2025-01-01 14:42:04浏览次数:5  
标签:Web null Java Spring request context import logger DispatcherServlet

1 概述:Spring Web DispatcherServlet

DispatcherServlet 简介

  • org.springframework.web.servlet.DispatcherServlet 是一个 Servlet,它接收所有的 HTTP 请求,并根据请求的信息将其分发给相应的处理器(Handler)进行处理。
  • 它是 Spring MVC 架构模式中的关键部分,将请求处理逻辑与实际的业务逻辑解耦,使得代码结构更加清晰和易于维护。

https://github.com/spring-projects/spring-framework/blob/v5.2.15.RELEASE/spring-webmvc/src/main/java/org/springframework/web/servlet/DispatcherServlet.java

2 DispatcherServlet 的初始化

Step1 Servlet 容器启动

  • 当 Web 应用启动时,Servlet 容器(如 Tomcat)会加载和初始化所有配置的 Servlet
  • 对于 DispatcherServlet,它的初始化过程在这个阶段开始。

Step2 读取配置

Step2.1 Servlet 初始化参数

  • DispatcherServlet 可以从 web.xml(传统方式)或者基于 Java 的配置(如使用@WebServlet注解)中获取初始化参数。

这些参数可以指定配置文件的位置、Spring 应用上下文的名称等信息。
例如,在传统的 web.xml 配置中,可以如下设置:

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/springmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
  • 这里指定了contextConfigLocation参数,告诉 DispatcherServlet 去哪里寻找 Spring MVC 的配置文件。

load-on-startup参数的值大于 0,表示在容器启动时就初始化该 Servlet

Step2.2 加载 Spring 配置文件

  • 根据配置的contextConfigLocation参数,DispatcherServlet 会加载 Spring 的配置文件。

在这个配置文件中,可以定义各种 Spring 组件,如视图解析器、处理器映射器、处理器适配器等。
这些组件对于后续的请求处理至关重要。

Step3 创建 Web 应用上下文

根上下文与子上下文

  • DispatcherServlet 会创建自己的 Web 应用上下文(通常是WebApplicationContext类型)。

这个上下文是整个 Spring MVC 应用的核心。
在一些复杂的应用中,可能还存在根上下文(由ContextLoaderListener创建),而 DispatcherServlet 的上下文是根上下文的子上下文。

组件扫描与初始化

  • 在创建 Web 应用上下文的过程中,会根据配置进行组件扫描
  • 它会查找并实例化所有配置的 Spring 组件,包括控制器(Controller)、服务(Service)等相关类。
  • 同时,会初始化在配置文件中定义的各种 bean,如视图解析器(ViewResolver)会被创建并配置好相应的视图解析策略。

深入分析:Spring Web DispatcherServlet 注册 Serlvet 的过程

Servlet 的注册: 传统 Servlet vs. Servlet 3

  • 传统的Servlet注册是配置在/WEB-INF/web.xml下,在容器启动的时候注册Servlet

  • Servlet 3规范为我们又提供了一种更加方便的注册方法————容器启动的时候扫描jar包,找到jar包下一个为如下文件路径的文件。

META-INF/services/javax.servlet.ServletContainerInitializer

该文件的内容必须是一个实现了javax.servlet.ServletContainerInitializer接口的实现类,该接口下有一个方法会自动被调用。

public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException 

其中第一个参数是一个Set,当该实现类上有注解@HandlesTypes,注解的value属性是一个Class[],这个数组及其子类(或实现类)会被注入到webAppInitializerClasses参数中。

Spring Web DispatcherServlet 注册过程

下面我们看看Spring是如何利用Servlet 3这种方式完成DispatcherServlet的注册。

ServletContainerInitializer

  • spring-web模块下,META-INF/services/javax.servlet.ServletContainerInitializer文件中的内容为:
org.springframework.web.SpringServletContainerInitializer

SpringServletContainerInitializer

  • 该类实现了ServletContainerInitializer接口,并标有@HandlesTypes注解。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.web;

import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.HandlesTypes;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;

@HandlesTypes({WebApplicationInitializer.class}) // 关键注解 : HandlesTypes
public class SpringServletContainerInitializer implements ServletContainerInitializer { // 关键接口 : 实现了 Servlet 3 规范的 ServletContainerInitializer 接口
    public SpringServletContainerInitializer() {
    }

    //关键方法: onStartup 
    public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
        List<WebApplicationInitializer> initializers = new LinkedList();
        Iterator var4;
        if (webAppInitializerClasses != null) {
            var4 = webAppInitializerClasses.iterator();

            while(var4.hasNext()) {
                Class<?> waiClass = (Class)var4.next();
                if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                    try {
                        initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass, new Class[0]).newInstance());
                    } catch (Throwable var7) {
                        throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
                    }
                }
            }
        }

        if (initializers.isEmpty()) {
            servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
        } else {
            servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
            AnnotationAwareOrderComparator.sort(initializers);
            var4 = initializers.iterator();

            while(var4.hasNext()) {
                WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
                initializer.onStartup(servletContext);
            }

        }
    }
}

onStartup方法:

  • 会将WebApplicationInitializer的实现类实例放到List中排序,依次调用onStartup()方法。
  • Spring为我们提供了一个WebApplicationInitializer的抽象实现类AbstractAnnotationConfigDispatcherServletInitializer,通常我们只需要继承此类来完成DispatcherServletspring context的注册。

AbstractDispatcherServletInitializer#onStartup

AbstractAnnotationConfigDispatcherServletInitializer的父类AbstractDispatcherServletInitializer覆盖了onStartup()方法:

//org.springframework.web.servlet.support.AbstractDispatcherServletInitializer

public void onStartup(ServletContext servletContext) throws ServletException {
   super.onStartup(servletContext);
   registerDispatcherServlet(servletContext);
}

首先,调用父类的方法完成root WebApplicationContext的初始化;
然后,调用registerDispatcherServlet()方法完成DispatcherServlet的注册。

AbstractDispatcherServletInitializer#registerDispatcherServlet

//org.springframework.web.servlet.support.AbstractDispatcherServletInitializer

protected void registerDispatcherServlet(javax.servlet.ServletContext servletContext) {
   String servletName = getServletName();
   Assert.hasLength(servletName, "getServletName() must not return empty or null");
   WebApplicationContext servletAppContext = createServletApplicationContext();
   Assert.notNull(servletAppContext,
         "createServletApplicationContext() did not return an application " +
         "context for servlet [" + servletName + "]");
   FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
   dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
   ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
   Assert.notNull(registration,
         "Failed to register servlet with name '" + servletName + "'." +
         "Check if there is another servlet registered under the same name.");
   registration.setLoadOnStartup(1);
   registration.addMapping(getServletMappings());
   registration.setAsyncSupported(isAsyncSupported());
   Filter[] filters = getServletFilters();
   if (!ObjectUtils.isEmpty(filters)) {
      for (Filter filter : filters) {
         registerServletFilter(servletContext, filter);
      }
   }
   customizeRegistration(registration);
}

暂时只关注Servlet的注册,Spring容器相关的以后介绍,createDispatcherServlet()方法创建了一个DispatcherServlet实例,然后通过servletContext.addServlet()方法完成DispatcherServlet的注册。

protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
   return new DispatcherServlet(servletAppContext);
}

以上就是DispatcherServlet的注册过程。

3 DispatcherServlet 的工作流程

Step1 接收请求

当一个 HTTP 请求到达 Servlet 容器时,容器会根据请求的 URL 将其路由到相应的 Servlet。对于匹配 DispatcherServlet 的请求(通常是通过 Servlet 映射配置),DispatcherServlet 开始处理这个请求。

Step2 请求处理准备

请求的解析与封装

  • DispatcherServlet 首先会对请求进行解析,将 HTTP 请求中的信息(如请求方法、请求参数、请求头、请求路径等)封装到HttpServletRequest对象中。这个对象将在整个请求处理过程中传递和使用。

获取处理器映射器(HandlerMapping)

  • DispatcherServlet 会从其初始化创建的 Web 应用上下文中获取处理器映射器。处理器映射器的作用是根据请求的信息(主要是 URL)找到处理该请求的处理器(Handler)。Spring 提供了多种类型的处理器映射器,如RequestMappingHandlerMapping等,它们通过不同的策略来确定处理器。

Step3 查找处理器

根据请求查找处理器

  • 处理器映射器会根据请求的 URL、请求方法等信息在已经注册的处理器中查找匹配的处理器。例如,如果使用@RequestMapping注解来定义控制器方法的映射,处理器映射器会根据请求的 URL 模式和请求方法(如 GET、POST 等)来确定对应的@RequestMapping注解标注的方法。

返回处理器执行链(HandlerExecutionChain)

  • 一旦找到匹配的处理器,处理器映射器会返回一个包含处理器和相关拦截器(Interceptor)的处理器执行链。拦截器可以在处理器执行前后执行一些额外的逻辑,如权限验证、日志记录等。

Step4 获取处理器适配器(HandlerAdapter)

选择合适的适配器

  • DispatcherServlet 根据处理器的类型从 Web 应用上下文中获取合适的处理器适配器。不同类型的处理器(如基于方法的处理器、基于控制器类的处理器等)需要不同的适配器来执行。

例如,对于使用@RequestMapping注解的处理器方法,会使用RequestMappingHandlerAdapter。

调用处理器适配器执行处理器

  • 处理器适配器负责调用处理器的具体方法,并将请求相关的参数传递给处理器。

在执行过程中,处理器(通常是控制器方法)会执行业务逻辑,可能涉及到调用服务层、数据访问层等,最终返回一个模型和视图(ModelAndView)对象或者其他类型的结果(如直接返回数据等情况)。

Step5 视图解析

获取视图解析器(ViewResolver)

  • 如果处理器返回了一个ModelAndView对象,DispatcherServlet 会从 Web 应用上下文中获取视图解析器。视图解析器根据ModelAndView中指定的视图名称和其他相关信息来确定实际的视图实现。

解析视图

  • 不同的视图解析器有不同的解析策略。例如,InternalResourceViewResolver可以将视图名称解析为 JSP 文件的路径。视图解析器会返回一个View对象,这个对象负责渲染最终的视图。

Step6 视图渲染与响应返回

渲染视图

  • View对象会根据模型数据(如果有)和请求信息对视图进行渲染。如果是 JSP 视图,会将模型数据填充到 JSP 页面中,然后生成最终的 HTML 内容。

返回响应

  • 渲染后的视图内容会被封装到HttpServletResponse对象中,并通过 Servlet 容器返回给客户端,完成整个请求处理流程。

小结

  • 总之,DispatcherServlet 在 Spring MVC 应用中起着至关重要的作用,它的初始化过程构建了整个请求处理的基础架构,而其工作流程则有条不紊地处理每个请求,将用户的请求转化为最终的响应,为开发高效、可维护的 Web 应用提供了有力的支持。

Y DispatcherServlet 完整源码

spring-webmvc : 5.2.15.RELEASE

package/import

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.web.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.core.log.LogFormatUtils;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.ui.context.ThemeSource;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.async.WebAsyncManager;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.util.NestedServletException;
import org.springframework.web.util.WebUtils;

DispatcherServlet extends FrameworkServlet、属性

public class DispatcherServlet extends FrameworkServlet {
    public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
    public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
    public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
    public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
    public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
    public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
    public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
    public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
    public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
    public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";
    public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
    public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";
    public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";
    public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP";
    public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP";
    public static final String FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER";
    public static final String EXCEPTION_ATTRIBUTE = DispatcherServlet.class.getName() + ".EXCEPTION";
    public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
    private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
    private static final String DEFAULT_STRATEGIES_PREFIX = "org.springframework.web.servlet";
    protected static final Log pageNotFoundLogger = LogFactory.getLog("org.springframework.web.servlet.PageNotFound");
    private static final Properties defaultStrategies;
    private boolean detectAllHandlerMappings = true;
    private boolean detectAllHandlerAdapters = true;
    private boolean detectAllHandlerExceptionResolvers = true;
    private boolean detectAllViewResolvers = true;
    private boolean throwExceptionIfNoHandlerFound = false;
    private boolean cleanupAfterInclude = true;

    @Nullable
    private MultipartResolver multipartResolver;
    @Nullable
    private LocaleResolver localeResolver;
    @Nullable
    private ThemeResolver themeResolver;
    @Nullable
    private List<HandlerMapping> handlerMappings;
    @Nullable
    private List<HandlerAdapter> handlerAdapters;
    @Nullable
    private List<HandlerExceptionResolver> handlerExceptionResolvers;
    @Nullable
    private RequestToViewNameTranslator viewNameTranslator;
    @Nullable
    private FlashMapManager flashMapManager;
    @Nullable
    private List<ViewResolver> viewResolvers;

构造器

    public DispatcherServlet() {
        this.setDispatchOptionsRequest(true);
    }

    public DispatcherServlet(WebApplicationContext webApplicationContext) {
        super(webApplicationContext);
        this.setDispatchOptionsRequest(true);
    }

方法/代码块

setDetectAllHandlerMappings/setDetectAllHandlerAdapters/setDetectAllHandlerExceptionResolvers/setDetectAllViewResolvers/setThrowExceptionIfNoHandlerFound/setCleanupAfterInclude

    public void setDetectAllHandlerMappings(boolean detectAllHandlerMappings) {
        this.detectAllHandlerMappings = detectAllHandlerMappings;
    }

    public void setDetectAllHandlerAdapters(boolean detectAllHandlerAdapters) {
        this.detectAllHandlerAdapters = detectAllHandlerAdapters;
    }

    public void setDetectAllHandlerExceptionResolvers(boolean detectAllHandlerExceptionResolvers) {
        this.detectAllHandlerExceptionResolvers = detectAllHandlerExceptionResolvers;
    }

    public void setDetectAllViewResolvers(boolean detectAllViewResolvers) {
        this.detectAllViewResolvers = detectAllViewResolvers;
    }

    public void setThrowExceptionIfNoHandlerFound(boolean throwExceptionIfNoHandlerFound) {
        this.throwExceptionIfNoHandlerFound = throwExceptionIfNoHandlerFound;
    }

    public void setCleanupAfterInclude(boolean cleanupAfterInclude) {
        this.cleanupAfterInclude = cleanupAfterInclude;
    }

onRefresh

    protected void onRefresh(ApplicationContext context) {
        this.initStrategies(context);
    }

initStrategies/initMultipartResolver/initLocaleResolver/initThemeResolver

    protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

    private void initMultipartResolver(ApplicationContext context) {
        try {
            this.multipartResolver = (MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Detected " + this.multipartResolver);
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
            }
        } catch (NoSuchBeanDefinitionException var3) {
            this.multipartResolver = null;
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No MultipartResolver 'multipartResolver' declared");
            }
        }

    }

    private void initLocaleResolver(ApplicationContext context) {
        try {
            this.localeResolver = (LocaleResolver)context.getBean("localeResolver", LocaleResolver.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Detected " + this.localeResolver);
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());
            }
        } catch (NoSuchBeanDefinitionException var3) {
            this.localeResolver = (LocaleResolver)this.getDefaultStrategy(context, LocaleResolver.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No LocaleResolver 'localeResolver': using default [" + this.localeResolver.getClass().getSimpleName() + "]");
            }
        }

    }

    private void initThemeResolver(ApplicationContext context) {
        try {
            this.themeResolver = (ThemeResolver)context.getBean("themeResolver", ThemeResolver.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Detected " + this.themeResolver);
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Detected " + this.themeResolver.getClass().getSimpleName());
            }
        } catch (NoSuchBeanDefinitionException var3) {
            this.themeResolver = (ThemeResolver)this.getDefaultStrategy(context, ThemeResolver.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No ThemeResolver 'themeResolver': using default [" + this.themeResolver.getClass().getSimpleName() + "]");
            }
        }

    }

initHandlerMappings/initHandlerAdapters

    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
        if (this.detectAllHandlerMappings) {
            Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList(matchingBeans.values());
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        } else {
            try {
                HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            } catch (NoSuchBeanDefinitionException var3) {
            }
        }

        if (this.handlerMappings == null) {
            this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
            }
        }

    }

    private void initHandlerAdapters(ApplicationContext context) {
        this.handlerAdapters = null;
        if (this.detectAllHandlerAdapters) {
            Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerAdapters = new ArrayList(matchingBeans.values());
                AnnotationAwareOrderComparator.sort(this.handlerAdapters);
            }
        } else {
            try {
                HandlerAdapter ha = (HandlerAdapter)context.getBean("handlerAdapter", HandlerAdapter.class);
                this.handlerAdapters = Collections.singletonList(ha);
            } catch (NoSuchBeanDefinitionException var3) {
            }
        }

        if (this.handlerAdapters == null) {
            this.handlerAdapters = this.getDefaultStrategies(context, HandlerAdapter.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No HandlerAdapters declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
            }
        }

    }

initHandlerExceptionResolvers

    private void initHandlerExceptionResolvers(ApplicationContext context) {
        this.handlerExceptionResolvers = null;
        if (this.detectAllHandlerExceptionResolvers) {
            Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerExceptionResolvers = new ArrayList(matchingBeans.values());
                AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
            }
        } else {
            try {
                HandlerExceptionResolver her = (HandlerExceptionResolver)context.getBean("handlerExceptionResolver", HandlerExceptionResolver.class);
                this.handlerExceptionResolvers = Collections.singletonList(her);
            } catch (NoSuchBeanDefinitionException var3) {
            }
        }

        if (this.handlerExceptionResolvers == null) {
            this.handlerExceptionResolvers = this.getDefaultStrategies(context, HandlerExceptionResolver.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No HandlerExceptionResolvers declared in servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
            }
        }

    }

initRequestToViewNameTranslator

    private void initRequestToViewNameTranslator(ApplicationContext context) {
        try {
            this.viewNameTranslator = (RequestToViewNameTranslator)context.getBean("viewNameTranslator", RequestToViewNameTranslator.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Detected " + this.viewNameTranslator);
            }
        } catch (NoSuchBeanDefinitionException var3) {
            this.viewNameTranslator = (RequestToViewNameTranslator)this.getDefaultStrategy(context, RequestToViewNameTranslator.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No RequestToViewNameTranslator 'viewNameTranslator': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");
            }
        }

    }

initViewResolvers

    private void initViewResolvers(ApplicationContext context) {
        this.viewResolvers = null;
        if (this.detectAllViewResolvers) {
            Map<String, ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.viewResolvers = new ArrayList(matchingBeans.values());
                AnnotationAwareOrderComparator.sort(this.viewResolvers);
            }
        } else {
            try {
                ViewResolver vr = (ViewResolver)context.getBean("viewResolver", ViewResolver.class);
                this.viewResolvers = Collections.singletonList(vr);
            } catch (NoSuchBeanDefinitionException var3) {
            }
        }

        if (this.viewResolvers == null) {
            this.viewResolvers = this.getDefaultStrategies(context, ViewResolver.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No ViewResolvers declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
            }
        }

    }

initFlashMapManager

    private void initFlashMapManager(ApplicationContext context) {
        try {
            this.flashMapManager = (FlashMapManager)context.getBean("flashMapManager", FlashMapManager.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Detected " + this.flashMapManager.getClass().getSimpleName());
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Detected " + this.flashMapManager);
            }
        } catch (NoSuchBeanDefinitionException var3) {
            this.flashMapManager = (FlashMapManager)this.getDefaultStrategy(context, FlashMapManager.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No FlashMapManager 'flashMapManager': using default [" + this.flashMapManager.getClass().getSimpleName() + "]");
            }
        }

    }

getThemeSource/getMultipartResolver/getHandlerMappings

    @Nullable
    public final ThemeSource getThemeSource() {
        return this.getWebApplicationContext() instanceof ThemeSource ? (ThemeSource)this.getWebApplicationContext() : null;
    }

    @Nullable
    public final MultipartResolver getMultipartResolver() {
        return this.multipartResolver;
    }

    @Nullable
    public final List<HandlerMapping> getHandlerMappings() {
        return this.handlerMappings != null ? Collections.unmodifiableList(this.handlerMappings) : null;
    }

getDefaultStrategy/getDefaultStrategies/createDefaultStrategy

    protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
        List<T> strategies = this.getDefaultStrategies(context, strategyInterface);
        if (strategies.size() != 1) {
            throw new BeanInitializationException("DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
        } else {
            return strategies.get(0);
        }
    }

    protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
        String key = strategyInterface.getName();
        String value = defaultStrategies.getProperty(key);
        if (value == null) {
            return new LinkedList();
        } else {
            String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
            List<T> strategies = new ArrayList(classNames.length);
            String[] var7 = classNames;
            int var8 = classNames.length;

            for(int var9 = 0; var9 < var8; ++var9) {
                String className = var7[var9];

                try {
                    Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                    Object strategy = this.createDefaultStrategy(context, clazz);
                    strategies.add(strategy);
                } catch (ClassNotFoundException var13) {
                    throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var13);
                } catch (LinkageError var14) {
                    throw new BeanInitializationException("Unresolvable class definition for DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var14);
                }
            }

            return strategies;
        }
    }

    protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
        return context.getAutowireCapableBeanFactory().createBean(clazz);
    }

doService

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        this.logRequest(request);
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap();
            Enumeration attrNames = request.getAttributeNames();

            label95:
            while(true) {
                String attrName;
                do {
                    if (!attrNames.hasMoreElements()) {
                        break label95;
                    }

                    attrName = (String)attrNames.nextElement();
                } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }

        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
        if (this.flashMapManager != null) {
            FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
            if (inputFlashMap != null) {
                request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
            }

            request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
            request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
        }

        try {
            this.doDispatch(request, response);
        } finally {
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
                this.restoreAttributesAfterInclude(request, attributesSnapshot);
            }

        }

    }

logRequest

    private void logRequest(HttpServletRequest request) {
        LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
            String params;
            if (this.isEnableLoggingRequestDetails()) {
                params = (String)request.getParameterMap().entrySet().stream().map((entry) -> {
                    return (String)entry.getKey() + ":" + Arrays.toString((Object[])entry.getValue());
                }).collect(Collectors.joining(", "));
            } else {
                params = request.getParameterMap().isEmpty() ? "" : "masked";
            }

            String queryString = request.getQueryString();
            String queryClause = StringUtils.hasLength(queryString) ? "?" + queryString : "";
            String dispatchType = !request.getDispatcherType().equals(DispatcherType.REQUEST) ? "\"" + request.getDispatcherType().name() + "\" dispatch for " : "";
            String message = dispatchType + request.getMethod() + " \"" + getRequestUri(request) + queryClause + "\", parameters={" + params + "}";
            if (traceOn) {
                List<String> values = Collections.list(request.getHeaderNames());
                String headers = values.size() > 0 ? "masked" : "";
                if (this.isEnableLoggingRequestDetails()) {
                    headers = (String)values.stream().map((name) -> {
                        return name + ":" + Collections.list(request.getHeaders(name));
                    }).collect(Collectors.joining(", "));
                }

                return message + ", headers={" + headers + "} in DispatcherServlet '" + this.getServletName() + "'";
            } else {
                return message;
            }
        });
    }

doDispatch

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }

                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    boolean isGet = "GET".equals(method);
                    if (isGet || "HEAD".equals(method)) {
                        long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                        if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                            return;
                        }
                    }

                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }

                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
            } catch (Throwable var23) {
                this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
            }

        } finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else if (multipartRequestParsed) {
                this.cleanupMultipart(processedRequest);
            }

        }
    }

applyDefaultViewName

    private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
        if (mv != null && !mv.hasView()) {
            String defaultViewName = this.getDefaultViewName(request);
            if (defaultViewName != null) {
                mv.setViewName(defaultViewName);
            }
        }

    }

processDispatchResult

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
        boolean errorView = false;
        if (exception != null) {
            if (exception instanceof ModelAndViewDefiningException) {
                this.logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException)exception).getModelAndView();
            } else {
                Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
                mv = this.processHandlerException(request, response, handler, exception);
                errorView = mv != null;
            }
        }

        if (mv != null && !mv.wasCleared()) {
            this.render(mv, request, response);
            if (errorView) {
                WebUtils.clearErrorRequestAttributes(request);
            }
        } else if (this.logger.isTraceEnabled()) {
            this.logger.trace("No view rendering, null ModelAndView returned.");
        }

        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
            }

        }
    }

buildLocaleContext

    protected LocaleContext buildLocaleContext(HttpServletRequest request) {
        LocaleResolver lr = this.localeResolver;
        return lr instanceof LocaleContextResolver ? ((LocaleContextResolver)lr).resolveLocaleContext(request) : () -> {
            return lr != null ? lr.resolveLocale(request) : request.getLocale();
        };
    }

checkMultipart

    protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
        if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
            if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
                if (request.getDispatcherType().equals(DispatcherType.REQUEST)) {
                    this.logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
                }
            } else if (this.hasMultipartException(request)) {
                this.logger.debug("Multipart resolution previously failed for current request - skipping re-resolution for undisturbed error rendering");
            } else {
                try {
                    return this.multipartResolver.resolveMultipart(request);
                } catch (MultipartException var3) {
                    if (request.getAttribute("javax.servlet.error.exception") == null) {
                        throw var3;
                    }
                }

                this.logger.debug("Multipart resolution failed for error dispatch", var3);
            }
        }

        return request;
    }

hasMultipartException

    private boolean hasMultipartException(HttpServletRequest request) {
        for(Throwable error = (Throwable)request.getAttribute("javax.servlet.error.exception"); error != null; error = error.getCause()) {
            if (error instanceof MultipartException) {
                return true;
            }
        }

        return false;
    }

cleanupMultipart

    protected void cleanupMultipart(HttpServletRequest request) {
        if (this.multipartResolver != null) {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
            if (multipartRequest != null) {
                this.multipartResolver.cleanupMultipart(multipartRequest);
            }
        }

    }

getHandler

    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();

            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                HandlerExecutionChain handler = mapping.getHandler(request);
                if (handler != null) {
                    return handler;
                }
            }
        }

        return null;
    }

noHandlerFound

    protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (pageNotFoundLogger.isWarnEnabled()) {
            pageNotFoundLogger.warn("No mapping for " + request.getMethod() + " " + getRequestUri(request));
        }

        if (this.throwExceptionIfNoHandlerFound) {
            throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request), (new ServletServerHttpRequest(request)).getHeaders());
        } else {
            response.sendError(404);
        }
    }

getHandlerAdapter

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        if (this.handlerAdapters != null) {
            Iterator var2 = this.handlerAdapters.iterator();

            while(var2.hasNext()) {
                HandlerAdapter adapter = (HandlerAdapter)var2.next();
                if (adapter.supports(handler)) {
                    return adapter;
                }
            }
        }

        throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

processHandlerException

    @Nullable
    protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception {
        request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
        ModelAndView exMv = null;
        if (this.handlerExceptionResolvers != null) {
            Iterator var6 = this.handlerExceptionResolvers.iterator();

            while(var6.hasNext()) {
                HandlerExceptionResolver resolver = (HandlerExceptionResolver)var6.next();
                exMv = resolver.resolveException(request, response, handler, ex);
                if (exMv != null) {
                    break;
                }
            }
        }

        if (exMv != null) {
            if (exMv.isEmpty()) {
                request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
                return null;
            } else {
                if (!exMv.hasView()) {
                    String defaultViewName = this.getDefaultViewName(request);
                    if (defaultViewName != null) {
                        exMv.setViewName(defaultViewName);
                    }
                }

                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Using resolved error view: " + exMv, ex);
                } else if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Using resolved error view: " + exMv);
                }

                WebUtils.exposeErrorRequestAttributes(request, ex, this.getServletName());
                return exMv;
            }
        } else {
            throw ex;
        }
    }

render

    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
        response.setLocale(locale);
        String viewName = mv.getViewName();
        View view;
        if (viewName != null) {
            view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
            if (view == null) {
                throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
            }
        } else {
            view = mv.getView();
            if (view == null) {
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
            }
        }

        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Rendering view [" + view + "] ");
        }

        try {
            if (mv.getStatus() != null) {
                response.setStatus(mv.getStatus().value());
            }

            view.render(mv.getModelInternal(), request, response);
        } catch (Exception var8) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Error rendering view [" + view + "]", var8);
            }

            throw var8;
        }
    }

getDefaultViewName/resolveViewName

    @Nullable
    protected String getDefaultViewName(HttpServletRequest request) throws Exception {
        return this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null;
    }

    @Nullable
    protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception {
        if (this.viewResolvers != null) {
            Iterator var5 = this.viewResolvers.iterator();

            while(var5.hasNext()) {
                ViewResolver viewResolver = (ViewResolver)var5.next();
                View view = viewResolver.resolveViewName(viewName, locale);
                if (view != null) {
                    return view;
                }
            }
        }

        return null;
    }

triggerAfterCompletion

    private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, Exception ex) throws Exception {
        if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, ex);
        }

        throw ex;
    }

restoreAttributesAfterInclude

    private void restoreAttributesAfterInclude(HttpServletRequest request, Map<?, ?> attributesSnapshot) {
        Set<String> attrsToCheck = new HashSet();
        Enumeration attrNames = request.getAttributeNames();

        while(true) {
            String attrName;
            do {
                if (!attrNames.hasMoreElements()) {
                    attrsToCheck.addAll(attributesSnapshot.keySet());
                    Iterator var8 = attrsToCheck.iterator();

                    while(var8.hasNext()) {
                        String attrName = (String)var8.next();
                        Object attrValue = attributesSnapshot.get(attrName);
                        if (attrValue == null) {
                            request.removeAttribute(attrName);
                        } else if (attrValue != request.getAttribute(attrName)) {
                            request.setAttribute(attrName, attrValue);
                        }
                    }

                    return;
                }

                attrName = (String)attrNames.nextElement();
            } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));

            attrsToCheck.add(attrName);
        }
    }

getRequestUri

    private static String getRequestUri(HttpServletRequest request) {
        String uri = (String)request.getAttribute("javax.servlet.include.request_uri");
        if (uri == null) {
            uri = request.getRequestURI();
        }

        return uri;
    }

static 块

    static {
        try {
            ClassPathResource resource = new ClassPathResource("DispatcherServlet.properties", DispatcherServlet.class);
            defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
        } catch (IOException var1) {
            throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + var1.getMessage());
        }
    }
}

X 参考文献

标签:Web,null,Java,Spring,request,context,import,logger,DispatcherServlet
From: https://www.cnblogs.com/johnnyzen/p/18471215

相关文章

  • WebApi使用 (.Net Framework版)
    1创建使用.Net做web后端,推荐使用.NetCore,微软在此基础上做了很多适配,包括内置Swagger,可以直接启动等等。而.NetFramework版,需要手动配置很多内容。如果需要调用的项目是基于.NetFramework,那么web项目也应基于.NetFramework开发。或者其他原因不得不使用.NetFramework开发w......
  • JAVA生成验证码
    1、生成方式(验证码字符串、图片验证码、base64验证码图片)/***@description:使用方式1:直接获取验证码字符串,前端进行自定义渲染*@date:2024/12/1611:37*@param*@returnjava.lang.String*/@GetMapping('/getCode')public......
  • Spring Data REST 远程代码执行漏洞(CVE-2017-8046)分析与复现12
    前言2009年9月Spring3.0RC1发布后,Spring就引入了SpEL(SpringExpressionLanguage)。对于开发者而言,引入新的工具显然是令人兴奋的,但是对于运维人员,也许是噩耗的开始。类比Struts2框架,会发现绝大部分的安全漏洞都和ognl脱不了干系。尤其是远程命令执行漏洞,占据了多少甲方乙方......
  • Spring Data REST 远程代码执行漏洞(CVE-2017-8046)分析与复现13
    前言2009年9月Spring3.0RC1发布后,Spring就引入了SpEL(SpringExpressionLanguage)。对于开发者而言,引入新的工具显然是令人兴奋的,但是对于运维人员,也许是噩耗的开始。类比Struts2框架,会发现绝大部分的安全漏洞都和ognl脱不了干系。尤其是远程命令执行漏洞,占据了多少甲方乙方......
  • Spring Data REST 远程代码执行漏洞(CVE-2017-8046)分析与复现1
    前言2009年9月Spring3.0RC1发布后,Spring就引入了SpEL(SpringExpressionLanguage)。对于开发者而言,引入新的工具显然是令人兴奋的,但是对于运维人员,也许是噩耗的开始。类比Struts2框架,会发现绝大部分的安全漏洞都和ognl脱不了干系。尤其是远程命令执行漏洞,占据了多少甲方乙方......
  • Spring Data REST 远程代码执行漏洞(CVE-2017-8046)分析与复现6
    前言2009年9月Spring3.0RC1发布后,Spring就引入了SpEL(SpringExpressionLanguage)。对于开发者而言,引入新的工具显然是令人兴奋的,但是对于运维人员,也许是噩耗的开始。类比Struts2框架,会发现绝大部分的安全漏洞都和ognl脱不了干系。尤其是远程命令执行漏洞,占据了多少甲方乙方......
  • Spring Data REST 远程代码执行漏洞(CVE-2017-8046)分析与复现9
    前言2009年9月Spring3.0RC1发布后,Spring就引入了SpEL(SpringExpressionLanguage)。对于开发者而言,引入新的工具显然是令人兴奋的,但是对于运维人员,也许是噩耗的开始。类比Struts2框架,会发现绝大部分的安全漏洞都和ognl脱不了干系。尤其是远程命令执行漏洞,占据了多少甲方乙方......
  • Spring Data REST 远程代码执行漏洞(CVE-2017-8046)分析与复现7
    前言2009年9月Spring3.0RC1发布后,Spring就引入了SpEL(SpringExpressionLanguage)。对于开发者而言,引入新的工具显然是令人兴奋的,但是对于运维人员,也许是噩耗的开始。类比Struts2框架,会发现绝大部分的安全漏洞都和ognl脱不了干系。尤其是远程命令执行漏洞,占据了多少甲方乙方......
  • [Java] Spring Event 发布-订阅模式:解耦与异步通信的高效实现
    序Spring框架通过发布/订阅模式为组件间通信提供了高效且松散耦合的解决方案,提升了系统的灵活性和扩展性。本文探讨该模式的原理、实现、应用场景及其优势与挑战。1发布订阅模式:基本概念发布-订阅模式,又称为观察者模式(ObserverPattern)的一种变体,是一种基于消息传递的设......
  • 记忆旅游系统|Java|SSM|VUE| 前后端分离
                  【技术栈】1⃣️:架构:B/S、MVC2⃣️:系统环境:Windowsh/Mac3⃣️:开发环境:IDEA、JDK1.8、Maven、Mysql5.7+4⃣️:技术栈:Java、Mysql、SSM、Mybatis-Plus、VUE、jquery,html5⃣️数据库可视化工具:navicat6⃣️服务器:SpringBoot自带apacheto......