SpringMVC对@Controller的处理

1、AnnotationConfigApplicationContext与AnnotationConfigWebApplicationContext

2、Spring如何解析@RequestMapping

3、web的自动配置

4、SpringMVC响应json数据

上一篇文章中说道DispatcherServlet会随着Tomcat容器启动,会调用DispatcherServlet的init初始化方法,在这个初始化方法中,这个servlet回去初始化spring的环境。

// FrameworkServlet#initServletBean
protected final void initServletBean() throws ServletException {
    // 初始化web环境 WebApplicationContext  ==child==> ConfigurableWebApplicationContext
    this.webApplicationContext = initWebApplicationContext();
    // 调用了initFrameworkServlet方法,这是一个空方法
    initFrameworkServlet();
}
// FrameworkServlet#configureAndRefreshWebApplicationContext
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
    // 设置ServletContext等属性
    wac.setServletContext(getServletContext());
    wac.setServletConfig(getServletConfig());
    wac.setNamespace(getNamespace());
    // 添加了一个监听器,监听容器刷新完成事件  DispatcherServlet#onRefresh 初始化SpringMVC组件
    wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
    // refresh的前置处理 设置环境的servlet上下文和servletConfig
    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
    }
    // 空方法
    postProcessWebApplicationContext(wac);
    // 调用容器的初始化方法 ApplicationContextInitializer#initialize接口的实现类
    applyInitializers(wac);
    // 刷新容器,走到AbstractApplicationContext中的refresh方法
    wac.refresh();
}

调用了AbstractApplicationContext#refresh,在这个方法中AnnotationConfigWebApplicationContext的webContext重写了postProcessBeanFactory方法

// AbstractRefreshableWebApplicationContext#postProcessBeanFactory
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 添加了一个BeanPostProcessor
    beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
    // 注册web环境
    WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}

ServletContextAwareProcessor这个BeanPostProcessor会在init方法执行之前为ServletContextAware设置servletContext属性

// ServletContextAwareProcessor#postProcessBeforeInitialization
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (getServletContext() != null && bean instanceof ServletContextAware) {
        ((ServletContextAware) bean).setServletContext(getServletContext());
    }
    if (getServletConfig() != null && bean instanceof ServletConfigAware) {
        ((ServletConfigAware) bean).setServletConfig(getServletConfig());
    }
    return bean;
}

处理@RequestMapping

处理入口:RequestMappingHandlerMapping


RequestMappingHandlerMapping.png

从上图可以看出RequestMappingHandlerMapping实现了InitializingBean接口,而这个对象会在SpringMVC初始化的时候有Spring来创建。

// RequestMappingHandlerMapping#afterPropertiesSet
public void afterPropertiesSet() {
    // 设置配置信息
    this.config = new RequestMappingInfo.BuilderConfiguration();
    // url路径解析工具  比如截取出uri ...
    this.config.setUrlPathHelper(getUrlPathHelper());
    // AntPathMatcher 路径匹配工具
    this.config.setPathMatcher(getPathMatcher());
    // 是否开启后缀匹配模式  默认true
    this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
    // 是否开启尾部/ 匹配   默认true
    this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
    this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
    this.config.setContentNegotiationManager(getContentNegotiationManager());
    super.afterPropertiesSet();
}
// 父类 AbstractHandlerMethodMapping#afterPropertiesSet
public void afterPropertiesSet() {
    initHandlerMethods();
}
protected void initHandlerMethods() {
    // 遍历spring中所有的object beanName
    for (String beanName : getCandidateBeanNames()) {
        // 是否以 scopedTarget. 开头
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            processCandidateBean(beanName);
        }
    }
    handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
    // bean class
    Class<?> beanType = obtainApplicationContext().getType(beanName);
    if (beanType != null && isHandler(beanType)) {
        // 筛选出Controller或者RequestMapping注解
        detectHandlerMethods(beanName);
    }
}
// 注意这里的isHandler判断
protected boolean isHandler(Class<?> beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
            AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

解析加了Controller或者RequestMapping注解的类

// AbstractHandlerMethodMapping#detectHandlerMethods  handler就是传入的bean对象
protected void detectHandlerMethods(Object handler) {
    Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());
    if (handlerType != null) {
        Class<?> userType = ClassUtils.getUserClass(handlerType);
        // 筛选出请求方法  合并请求uri
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                                (MethodIntrospector.MetadataLookup<T>) method -> {
                                    return getMappingForMethod(method, userType);
                                });
        // 注册方法映射
        methods.forEach((method, mapping) -> {
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}
// 方法的解析
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // 解析@RequestMapping 包括内部的各种属性 请求类型 映射路径 参数 ...
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        // 获取类上面的@RequestMapping注解
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        if (typeInfo != null) {
            // requestMapping合并
            info = typeInfo.combine(info);
        }
        // 获取类上面的前缀
        String prefix = getPathPrefix(handlerType);
        if (prefix != null) {
            // 进行前缀合并
            info = RequestMappingInfo.paths(prefix).build().combine(info);
        }
    }
    return info;
}

注册Controller映射对应关系

// 方法映射的注册
methods.forEach((method, mapping) -> {
    Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
    registerHandlerMethod(handler, invocableMethod, mapping);
});
// Controller中对方法的要求
public static Method selectInvocableMethod(Method method, @Nullable Class<?> targetType) {
    // 当前类的方法
    Method methodToUse = MethodIntrospector.selectInvocableMethod(method, targetType);
    // 私有方法 + 非静态方法 + SpringProxy子类 -> SpringProxy子类的私有方法会直接抛出异常
    if (Modifier.isPrivate(methodToUse.getModifiers()) 
        && !Modifier.isStatic(methodToUse.getModifiers()) 
        && SpringProxy.class.isAssignableFrom(targetType)) {
        throw new IllegalStateException("xxxx");
    }
}
// 映射的注册
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    this.mappingRegistry.register(mapping, handler, method);
}

注册的具体逻辑:AbstractHandlerMethodMapping.MappingRegistry#register

public void register(T mapping, Object handler, Method method) {
    // 写锁
    this.readWriteLock.writeLock().lock();
    try {
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        assertUniqueMethodMapping(handlerMethod, mapping);
        // 把 [mapping - handlerMethod] 放入mappingLookup
        // mapping就是当前方法的汇总注解信息
        this.mappingLookup.put(mapping, handlerMethod);
        List<String> directUrls = getDirectUrls(mapping);
        // urlLookup中放入的是 [uri - mapping]  {"/index",RequestMappingInfo}
        for (String url : directUrls) {
            this.urlLookup.add(url, mapping);
        }
        // 解析其他形式的uri 正则 后缀 矩阵 等
        String name = null;
        if (getNamingStrategy() != null) {
            name = getNamingStrategy().getName(handlerMethod, mapping);
            addMappingName(name, handlerMethod);
        }
        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            this.corsLookup.put(handlerMethod, corsConfig);
        }
        // 缓存已注册的信息
        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    } finally {
        this.readWriteLock.writeLock().unlock();
    }
}

@EnableWebMvc注解

@EnableWebMvc表示开启webmvc的自动配置,并且我们可以实现WebMvcConfigurer接口去添加SpringMVC的组件,比如:异常处理器、视图解析器、拦截器、消息转换器等等。

为什么我们实现并重写WebMvcConfigurer接口中的方法,spring就可以用到这些组件,就和这个注解有关。

spring在解决DelegatingWebMvcConfiguration的依赖时,回去容器中所有实现了WebMvcConfigurer接口的bean对象,返回注入到这里来。

源码参考:AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject

@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {}
// 导入的配置类
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    // WebMvcConfigurerComposite实现了WebMvcConfigurer接口
    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
    // 为set方法注入配置集合
    @Autowired(required = false)
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
    }
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        this.configurers.addInterceptors(registry);
    }
    //省略很多方法
}

重点分析WebMvcConfigurerComposite类

class WebMvcConfigurerComposite implements WebMvcConfigurer {
    // 配置类集合
    private final List<WebMvcConfigurer> delegates = new ArrayList<>();
    public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.delegates.addAll(configurers);
        }
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        for (WebMvcConfigurer delegate : this.delegates) {
            delegate.addInterceptors(registry);
        }
    }
}

在这个DelegatingWebMvcConfiguration类中只有一个@Bean,明显靠着一个bean对象是无法完成springmvc的,所以我们继续分析它的父类WebMvcConfigurationSupport。

// 这里面注入了很多的web组件 拦截器 异常处理器 视图解析器 处理器映射器 等等
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    // 主要看RequestMappingHandlerMapping
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
        // new RequestMappingHandlerMapping()
        RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
        mapping.setOrder(0);
        // 设置拦截器
        mapping.setInterceptors(getInterceptors());
        mapping.setContentNegotiationManager(mvcContentNegotiationManager());
        mapping.setCorsConfigurations(getCorsConfigurations());
        // .... 很多组件
        return mapping;
    }
    // 拦截器的获取逻辑
    protected final Object[] getInterceptors() {
        if (this.interceptors == null) {
            // 拦截器注册器
            InterceptorRegistry registry = new InterceptorRegistry();
            // 向configurers中添加注册器,这里其实就是注册程序中自己写的拦截
            addInterceptors(registry);
            // 注册两个拦截器 这两个拦截器都会被包装为InterceptorRegistration
            registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
            registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
            // 获取所有的拦截器(包括使用WebMvcConfigurer注册的)
            this.interceptors = registry.getInterceptors();
        }
        return this.interceptors.toArray();
    }
}

当使用WebMvcConfigurer去添加拦截器的时候,拦截器会被包装为InterceptorRegistration。

// InterceptorRegistry#addInterceptor
public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
    InterceptorRegistration registration = new InterceptorRegistration(interceptor);
    this.registrations.add(registration);
    return registration;
}
enableWebMvc拦截器的处理.png

SpringMVC响应json数据

我们都知道,要使springMVC可以响应json数据,必须要添加一个消息转换器。

@Configuration
public class WebMvcConfig  implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/index/2");
    }
    // 配置消息转换器
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(jsonHttpMessageConverter());
    }
    @Bean
    public FastJsonHttpMessageConverter jsonHttpMessageConverter() {
        return new FastJsonHttpMessageConverter();
    }
}

分析处理器处理请求的时候,以@RequestMapping为例,核心处理逻辑:RequestMappingHandlerAdapter#handleInternal

// RequestMappingHandlerAdapter的构造方法
public RequestMappingHandlerAdapter() {
    StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
    stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316
    // 添加了四个 messageConverter
    this.messageConverters = new ArrayList<>(4);
    this.messageConverters.add(new ByteArrayHttpMessageConverter());
    this.messageConverters.add(stringHttpMessageConverter);
    this.messageConverters.add(new SourceHttpMessageConverter<>());
    this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}

处理请求的方法调用过程

RequestMappingHandlerAdapter#handleInternal
 => RequestMappingHandlerAdapter#invokeHandlerMethod
    => ServletInvocableHandlerMethod#invokeAndHandle

主要看ServletInvocableHandlerMethod#invokeAndHandle方法

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,Object... providedArgs) throws Exception {
    // 调用了具体controller中的方法,获取了返回值
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    // 根据@ResponseStatus code 设置status
    setResponseStatus(webRequest);
    // 返回值为 null
    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            disableContentCachingIfNecessary(webRequest);
            mavContainer.setRequestHandled(true);
            return;
        }
    // 检查@ResponseStatus注解的reason
    } else if (StringUtils.hasText(getResponseStatusReason())) {
        mavContainer.setRequestHandled(true);
        return;
    }
    // 标记请求是否处理完成
    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        // 选择合适的结果处理器来处理结果集
        this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    } catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(formatErrorForReturnValue(returnValue), ex);
        }
        throw ex;
    }
}

结果处理器的选择

// HandlerMethodReturnValueHandlerComposite#handleReturnValue
public void handleReturnValue(Object returnValue, MethodParameter returnType,
                              ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    // 获取一个可以处理 returnType 的结果集处理器
    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
    if (handler == null) {
        // 如果找不到一个结果集处理器来处理,就会在这里抛出异常
        throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    }
    // 调用 handleReturnValue 来处理结果
    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
// HandlerMethodReturnValueHandlerComposite#selectHandler
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
    boolean isAsyncValue = isAsyncReturnValue(value, returnType);
    // 循环所有的结果处理器
    for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
        if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
            continue;
        }
        // 如果找到一个可以处理这个结果类型的处理器,就直接将这个处理器返回 supportsReturnType
        if (handler.supportsReturnType(returnType)) {
            return handler;
        }
    }
    return null;
}

已知存在的结果处理器有以下几种

# 处理ModelAndView类型的返回值
ModelAndViewMethodReturnValueHandler
# 处理Model类型的返回值
ModelMethodProcessor
# 处理View类型的返回值
ViewMethodReturnValueHandler
# 处理ResponseBodyEmitter类型
ResponseBodyEmitterReturnValueHandler
# 处理StreamingResponseBody类型
StreamingResponseBodyReturnValueHandler
# 处理HttpEntity和RequestEntity类型
HttpEntityMethodProcessor
# 处理HttpHeaders类型
HttpHeadersReturnValueHandler
# 处理Callable类型
CallableMethodReturnValueHandler
# 处理DeferredResult ListenableFuture和CompletionStage类型
DeferredResultMethodReturnValueHandler
# 处理WebAsyncTask
AsyncTaskMethodReturnValueHandler
# 处理ModelAttribute
ModelAttributeMethodProcessor
# 处理加了 @RequestBody 注解的返回值
RequestResponseBodyMethodProcessor
# 处理没有添加 @RequestBody 并返回string类型的返回  会解析成视图名称
ViewNameMethodReturnValueHandler
# 处理map返回值
MapMethodProcessor

判定规则就是调用每一个处理器的supportsReturnType方法,来找到可以处理这个返回值类型的处理器。

如果我们添加了@RequestBody注解,那么就会进入RequestResponseBodyMethodProcessor处理器。

// RequestResponseBodyMethodProcessor#supportsReturnType
public boolean supportsReturnType(MethodParameter returnType) {
    // 类或者方法上存在ResponseBody注解
    return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
            returnType.hasMethodAnnotation(ResponseBody.class));
}
// 调用 RequestResponseBodyMethodProcessor#handleReturnValue 方法处理返回值
public void handleReturnValue(Object returnValue, MethodParameter returnType,
                              ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
    throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
    // 标记为已处理
    mavContainer.setRequestHandled(true);
    ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
    ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
    // Try even with null return value. ResponseBodyAdvice could get involved.
    // 如果这个的返回值是void,那么会在 ResponseBodyAdvice 中处理
    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

确定响应的类型,调用spring中所有的messageConverters进行处理。下面贴出关键代码

// AbstractMessageConverterMethodProcessor#writeWithMessageConverters
// InputStreamResource 或者 Resource 类型
if (isResourceType(value, returnType)) {
    outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
}
MediaType contentType = outputMessage.getHeaders().getContentType();
// 遍历 messageConverters 来处理结果集
for (HttpMessageConverter<?> converter : this.messageConverters) {
   // 最终调用 messageConverter 将结果集write出去 -> FastJsonHttpMessageConverter#write
    genericConverter.write(body, targetType, selectedMediaType, outputMessage);
}

// AbstractHttpMessageConverter#write  t就是方法的返回值
public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage) {
    final HttpHeaders headers = outputMessage.getHeaders();
    // 添加默认的头信息
    addDefaultHeaders(headers, t, contentType);
    if (outputMessage instanceof StreamingHttpOutputMessage) {
        StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;
        // 调用FastJsonHttpMessageConverter#writeInternal
        streamingOutputMessage.setBody(outputStream -> writeInternal(t, new HttpOutputMessage() {
            @Override
            public OutputStream getBody() {
                return outputStream;
            }
            @Override
            public HttpHeaders getHeaders() {
                return headers;
            }
        }));
    }
}

最后就是使用一个ByteArrayOutputStream输出流将返回值写到HttpResponse的body中。

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容