问题描述

在SpringMVC中默认可以注入Model,ModelAndView,@RequestParam,@PathVariable 等,那么这个是怎么实现的,以及怎么注入一个自定义的参数呢

HandlerMethodArgumentResolver

在SpringMVC中有一个接口HandlerMethodArgumentResolver,这个就是用来控制解析controller中的参数类型来进行注入的,下面是一个自定义参数的例子

首先自定义resolver

public class MyHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
//用来判断参数是否支持当前resolver
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> klass = parameter.getParameterType();
if (klass == String.class) {//这里使用参数类型匹配,MethodParameter还包含了方法注解和参数注解信息,可以使用它们来进行识别
return true;
}
return false;
}
//真正返回要注入的值
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
return "custom string";
}
}

注册在配置文件中

	<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="web.controller.MyHandlerMethodArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>

之后就可以使用了

	@RequestMapping("test")
@ResponseBody
public String test(String a){
return a;
}

在页面访问test连接显示的就是自定义的“custom string”。

实现

下面来看下这个的实现,在MVC启动时会生成一个Resolver的Composite对象,这个包含了所有的注册的Resolver

在HandlerMethodArgumentResolverComposite中有如下几个方法

	//每个参数都会调用resolveArgument进行解析
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)throws Exception {
//获得对应的resolver
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
Assert.notNull(resolver, "Unknown parameter type [" + parameter.getParameterType().getName() + "]");
//使用resolver进行解析
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
//获得相应的resolver
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
//这里有个ConcurrentHashMap构成的cache可以避免重复的解析
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
//如果cache没有命中则进行解析
if (result == null) {
//遍历所有resolver
for (HandlerMethodArgumentResolver methodArgumentResolver : argumentResolvers) {
if (logger.isTraceEnabled()) {
logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
parameter.getGenericParameterType() + "]");
}
//找到对应resolver并存入cache
if (methodArgumentResolver.supportsParameter(parameter)) {
result = methodArgumentResolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}

那自定义的resolver是如何被springmvc探测到的呢,这里列出argumentResolvers初始化时的赋值

		// Annotation-based argument resolution
//基于注解的resolver明显有RequestParam,PathVariable等
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); // Type-based argument resolution
//基于类型的resolver如Request,Response等
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); // Custom arguments
//这里就是自定义的了resolver了
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
} // Catch-all
//垫底的resolver,第一个RequestParamMethodArgumentResolver与前面注册的第二个构造参数不同主要用来拦截未标注注解的普通变量(如CharSequence,Number,List等)
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));

总结

本文看了自定义controller参数的解析过程

SpringMVC自定义注入controller变量的更多相关文章

  1. SpringMVC常用注解@Controller,@Service,@repository,@Component

    SpringMVC常用注解@Controller,@Service,@repository,@Component controller层使用@controller注解 @Controller 用于标记 ...

  2. SpringMVC——自定义拦截器、异常处理以及父子容器配置

    自定义拦截器: 一.若想实现自定义拦截器,需要实现 org.springframework.web.servlet.HandlerInterceptor 接口. 二.HandlerIntercepto ...

  3. SpringMVC页面向Controller传参

    关于SpringMVC页面向Controller传参的问题,看了网上不少帖子,大多总结为以下几类: 1.直接把页面表单中相关元素的name属性对应的值作为Controller方法中的形参. 这个应该是 ...

  4. SpringMVC自定义类型转换器

    SpringMVC 自定义类型转换器  我们在使用SpringMVC时,常常需要把表单中的参数映射到我们对象的属性中,我们可以在默认的spring-servlet.xml加上如下的配置即可做到普通数据 ...

  5. ThinkPHP框架配置自定义的模板变量(十)

    原文:ThinkPHP框架配置自定义的模板变量(十) 模板替换(手册有详细介绍对应的目录) __PUBLIC__:会被替换成当前网站的公共目录 通常是 /Public/ __ROOT__: 会替换成当 ...

  6. Spring注入静态变量的方法,以及CXF如何获取客户端IP

    1.如果使用@Resource注解来注入静态变量的,服务器启动就会报错的.可以新增一个set方法,同时在set方法上用@Resource注解来注入. 2.或者直接在Spring的配置文件中使用< ...

  7. SpringBoot使用@Value从yml文件取值为空--注入静态变量

    SpringBoot使用@Value从yml文件取值为空--注入静态变量     1.application.yml中配置内容如下:   pcacmgr:   publicCertFilePath: ...

  8. SpringMVC自定义视图Excel视图和PDF视图

    SpringMVC自定义视图 Excel视图和PDF视图 SpringMVC杂记(十一) 使用Excel视图 Spring MVC 视图解析器(ViewResolver ) java实现导出excel ...

  9. SpringMvc问题记录-Controller对于静态变量的访问分析

    问题描述 在于朋友的讨论中分析到一种场景,即:Controller对于一个类中的静态变量进行访问时,如果第一个接口修改该静态变量的数据,另外一个接口获取该静态变量的数据,那么返回的结果是什么? 操作步 ...

随机推荐

  1. (一)常用的CSS命名规则

    头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体布局宽度:wrapper 左右中:left rig ...

  2. sqlserver2012 表分区

    无论是新建数据库,还是现有的问题,都可以执行表分区的操作. 1.在数据库中点鼠标右键点击属性,在选择页,选中文件栏,在数据库文件列表中,可以看到现有的数据库文件逻辑名称.文件类型.初始大小.保存位置等 ...

  3. 高流量站点NGINX与PHP-fpm配置优化(译)

    使用Nginx搭配PHP已有7年的这份经历让我们学会如何为高流量站点优化NGINX和PHP-fpm配置. 以下正是这方面的一些提示和建议: 1. 将TCP切换为UNIX域套接字 UNIX域套接字相比T ...

  4. Ubuntu MYSQL和Windows MYSQL (非C盘安装)

    1.Ubuntu 默认安装 Mysql 5.6版本以上: 1.查看系统是否安装mysql 数据库: sudo netstat -tap | grep mysql 如果安装了,就查看一下版本命令: my ...

  5. 【Visual Lisp】块专题

    ;;关于块 ;;(0)模型空间→块表记录→块图元:顶层的是模型空间→模型空间下有很多图元和一些块表记录→块表记录又有很多图元(此时块表记录就相当于模型空间),一个块表记录可以有多个insert块→同一 ...

  6. SA: 情感分析资源(Corpus、Dictionary)

    先主要摘自一篇中文Survey,http://wenku.baidu.com/view/0c33af946bec0975f465e277.html   4.2 情感分析的资源建设 4.2.1 情感分析 ...

  7. 测试文档锁:doc.LockDocument()

    /// <summary> /// 总结:用到DocumentManager.Open(filePath)时,如果是ForWrite,就需要用到lock文档锁. /// </summ ...

  8. Software Testing hw1

    I still remember the error which I made in my java project last year. I spent a whole night solving  ...

  9. mysql用户权限设置

    1.创建新用户 通过root用户登录之后创建 >> grant all privileges on *.* to testuser@localhost identified by &quo ...

  10. [转]mysql drop、truncate和delete比较

    一.drop table tb drop将表格直接删除,没有办法找回. 立刻释放磁盘空间 ,不管是 Innodb和MyISAM . 二.truncate (table) tb 该命令可以清空一个表里的 ...