IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringMvc 源码分析 (RequestMappingHandlerAdapter 的使用细节) (九) -> 正文阅读

[Java知识库]SpringMvc 源码分析 (RequestMappingHandlerAdapter 的使用细节) (九)

0.前记

根据之前的文章可知HandlerAdapter主要的是RequestMappingHandlerAdapter的效果

本章解释一下RequestMappingHandlerAdapter的具体使用情况

1.RequestMappingHandlerAdapter 的初始化

根据前文可知在DispatcherServlet初始化的时候会初始化HandlerAdapter

这里默认会初始化RequestMappingHandlerAdapter,RequestMappingHandlerAdapter 实现了InitializingBean接口

会实现afterPropertiesSet()方法

在这里插入图片描述

  1. 初始化@ControllerAdvice
  2. 初始化参数解析器 argumentResolvers
  3. 初始化绑定参数解析器 initBinderArgumentResolvers
  4. 初始化返回值解析器 returnValueHandlers

下面列举的都是参数解析器
在这里插入图片描述
以上就添加了参数解析器和返回值解析器

2.参数解析器解析

在这里插入图片描述
WebConfig.java

@Configuration
@ComponentScan
@PropertySource("classpath:application.properties")
@EnableConfigurationProperties({WebMvcProperties.class, ServerProperties.class})
public class WebConfig {
    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory(ServerProperties serverProperties){
        return new TomcatServletWebServerFactory(serverProperties.getPort());
    }

    // DispatcherServlet初始化时机: 创建是Spring创建的, 初始化为tomcat初始化的: 第一次请求的时候初始化, 可以设置为tomcat服务器启动就初始化好
    // 初始化: onRefresh()
    // RequestMappingHandlerMapping: 解析@RequestMapping 以及派生注解, 生成路径和控制器方法的映射关系,
    // RequestMappingHandlerAdaptor: 调用控制器方法
    @Bean
    public DispatcherServlet dispatcherServlet(){
        return new DispatcherServlet();
    }

    @Bean
    public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(WebMvcProperties webMvcProperties){
        DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatcherServlet(), "/");
        // tomcat启动的时候DS初始化完毕
        registrationBean.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
        return registrationBean;
    }

    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping(){
        return new RequestMappingHandlerMapping();
    }

    @Bean
    public MyRequestMappingHandlerAdapter requestMappingHandlerAdapter(){
        return new MyRequestMappingHandlerAdapter();
    }

}

MyRequestMappingHandlerAdapter.java

public class MyRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {
    @Override
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        return super.invokeHandlerMethod(request, response, handlerMethod);
    }
}

Controller1.java

@RestController
public class Controller1 {
    @GetMapping("/test1")
    public String test1(){
        System.out.println("1");
        return "1";
    }
}

A20.java

public class A20 {
    public static void main(String[] args) throws Exception {
        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);

        RequestMappingHandlerMapping handlerMapping = context.getBean(RequestMappingHandlerMapping.class);
        // 路径信息, 控制器方法
        Map<RequestMappingInfo, HandlerMethod> map = handlerMapping.getHandlerMethods();
        map.forEach((k, v) -> {
            System.out.println(k + " = " + v);
        });

        // 返回处理器执行链对象
        MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test1");
        MockHttpServletResponse response = new MockHttpServletResponse();
        HandlerExecutionChain chain = handlerMapping.getHandler(request);
        System.out.println(chain);

        MyRequestMappingHandlerAdapter handlerAdapter = context.getBean(MyRequestMappingHandlerAdapter.class);
        handlerAdapter.invokeHandlerMethod(request, response, (HandlerMethod) chain.getHandler());

        System.out.println(">>>>>>>> 参数解析器");
        for (HandlerMethodArgumentResolver argumentResolver : handlerAdapter.getArgumentResolvers()) {
            System.out.println(argumentResolver);
        }

        System.out.println(">>>>>>>> 返回值解析器");
        for (HandlerMethodReturnValueHandler returnValueHandler : handlerAdapter.getReturnValueHandlers()) {
            System.out.println(returnValueHandler);
        }

    }
}

获取到参数解析器和返回值解析器

在这里插入图片描述
在这里插入图片描述

模拟发生get请求

        MyRequestMappingHandlerAdapter handlerAdapter = context.getBean(MyRequestMappingHandlerAdapter.class);
        handlerAdapter.invokeHandlerMethod(request, response, (HandlerMethod) chain.getHandler());

在这里插入图片描述

3.自定义参数解析器

这里自定义了一个@Token, 用于解析参数的带有头信息的token值

在这里插入图片描述

  1. Token .java
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {
}
  1. TokenArgumentResolver.java
public class TokenArgumentResolver implements HandlerMethodArgumentResolver {
    // 是否支持某个参数
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        Token token = parameter.getParameterAnnotation(Token.class);

        return token != null;
    }

    // 解析参数
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        return webRequest.getHeader("token");
    }
}
  1. WebConfig.java

在这里插入图片描述

  1. Controller1.java

在这里插入图片描述

  1. A20.java

在这里插入图片描述

  1. 这里利用了模拟PUT请求/test2的, 并加入了token

在这里插入图片描述

4.参数解析器的执行过程

先拿到方法的参数, 然后解析, 最后通过反射执行

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

所以说最后是通过反射去执行方法的。

5.参数解析过程

在这里插入图片描述

	protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		MethodParameter[] parameters = getMethodParameters();
		if (ObjectUtils.isEmpty(parameters)) {
			return EMPTY_ARGS;
		}

		Object[] args = new Object[parameters.length];
		for (int i = 0; i < parameters.length; i++) {
			MethodParameter parameter = parameters[i];
			parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
			args[i] = findProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
			if (!this.resolvers.supportsParameter(parameter)) {
				throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
			}
			try {
				args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
			}
			catch (Exception ex) {
				// Leave stack trace for later, exception may actually be resolved and handled...
				if (logger.isDebugEnabled()) {
					String exMsg = ex.getMessage();
					if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
						logger.debug(formatArgumentError(parameter, exMsg));
					}
				}
				throw ex;
			}
		}
		return args;
	}
  1. 先找到提供的参数 findProvidedArgument
  2. 解析器进行解析 resolveArgument, 之前先判断解析器是否可以解析 supportsParameter
	private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
			for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
				if (resolver.supportsParameter(parameter)) {
					result = resolver;
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}

这里先看缓存有无, 第一次的话缓存肯定无, 那么就加入到缓存。这里为优化部分

下面的为实现了supportsParameter 方法的参数解析器

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 16:07:52  更:2022-07-17 16:13:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/22 7:56:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码