Spring MVC手动注册requestMapping

      之前写过一个Api Mock的小工具,没有什么高大上的技术,比较值得一提的是手动注册requestMapping。一般情况下,controller都是提前写好的,例如:

 /**
     * 检查接口序号是否已经占用
     * */
    @RequestMapping(value = "/getApiInfoByIndex.do", method = RequestMethod.POST)
    @ResponseBody
    public IResult getApiInfoByIndex(String index) {
        return new ResultBean<ApiBean>(requestMappingService.getApiInfoByIndex(index));
    }

        像这样写一个处理路由的方法,然后我们才能发起请求,然后被方法处理。而在Api Mock工具中,并不知道路由会是什么,这个是用户指定的,所以需要动态的去注册。

        Spring MVC是如何注册requestMapping的呢?通过翻看源码,这一部分工作由RequestMappingHandlerMapping这个类完成。RequestMappingHandlerMapping的父类AbstractHandlerMethodMapping中,提供了注册和注销的两个方法:

 public void registerMapping(T mapping, Object handler, Method method) {
        this.mappingRegistry.register(mapping, handler, method);
    }

    public void unregisterMapping(T mapping) {
        this.mappingRegistry.unregister(mapping);
    }

        mapping需要提供一个RequestMappingInfo类的实例,RequestMappingInfo其实就是@RequestMapping注解里面提供信息的一个包装类。按照我们一般的@RquestMapping的写法,我们只需要提供一个url和requestMethod就够了,而正好RequestMappingInfo提供的构造函数对很多参数都做了判空处理。因此对应着,我们只需要提供PatternsRequestCondition和RequestMehtodsRequestCondition两个参数即可,分别对应@RequestMapping里面的ur和rquestMethod。

public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
    private final String name;
    private final PatternsRequestCondition patternsCondition;
    private final RequestMethodsRequestCondition methodsCondition;
    private final ParamsRequestCondition paramsCondition;
    private final HeadersRequestCondition headersCondition;
    private final ConsumesRequestCondition consumesCondition;
    private final ProducesRequestCondition producesCondition;
    private final RequestConditionHolder customConditionHolder;

    public RequestMappingInfo(String name, PatternsRequestCondition patterns, RequestMethodsRequestCondition methods, ParamsRequestCondition params, HeadersRequestCondition headers, ConsumesRequestCondition consumes, ProducesRequestCondition produces, RequestCondition<?> custom) {
        this.name = StringUtils.hasText(name)?name:null;
        this.patternsCondition = patterns != null?patterns:new PatternsRequestCondition(new String[0]);
        this.methodsCondition = methods != null?methods:new RequestMethodsRequestCondition(new RequestMethod[0]);
        this.paramsCondition = params != null?params:new ParamsRequestCondition(new String[0]);
        this.headersCondition = headers != null?headers:new HeadersRequestCondition(new String[0]);
        this.consumesCondition = consumes != null?consumes:new ConsumesRequestCondition(new String[0]);
        this.producesCondition = produces != null?produces:new ProducesRequestCondition(new String[0]);
        this.customConditionHolder = new RequestConditionHolder(custom);
    }

        hanlder表示处理该url的类的实例,从源码中可以看到,提供实例的beanName就可以了。mehtod就更简单了,就是实例中的哪个方法来处理这个url,我们可以通过反射获取到。

        前面分析了一波,下面就是具体的操作方法了:

1、首先创建一个处理动态url的Controller和方法。

@Controller
@Slf4j
public class ApiController {
    @ResponseBody
    public String index1() {
        ApiBean apiBean = Constants.requestMappings.get("1");
        return getReturnMsg(apiBean.getMsg());
    }
   // 省略...
}

处理的方法index1中,我们并没有加上@RequestMapping注解,这个requestMapping我们将稍候进行注册。

2、进行注册

 RequestMappingHandlerMapping requestMappingHandlerMapping = webApplicationContext.getBean(RequestMappingHandlerMapping.class);
        Method targetMethod = ReflectionUtils.findMethod(ApiController.class, getHandlerMethodName(index)); // 找到处理该路由的方法

        PatternsRequestCondition patternsRequestCondition = new PatternsRequestCondition(api);
        RequestMethodsRequestCondition requestMethodsRequestCondition = new RequestMethodsRequestCondition(getRequestMethod(requestMethod));

        RequestMappingInfo mapping_info = new RequestMappingInfo(patternsRequestCondition, requestMethodsRequestCondition, null, null, null, null, null);
        requestMappingHandlerMapping.registerMapping(mapping_info, "apiController", targetMethod); // 注册映射处理

        这就是注册的核心代码,提供handler,method,生成requestMappingInfo对象,然后进行注册。这个注册是立即生效的,不需要重启应用。但是要注意防止重复注册,spring mvc似乎并没有判断重复。

3、注销

 RequestMappingHandlerMapping requestMappingHandlerMapping = webApplicationContext.getBean(RequestMappingHandlerMapping.class);
     
        PatternsRequestCondition patternsRequestCondition = new PatternsRequestCondition(api);
        RequestMethodsRequestCondition requestMethodsRequestCondition = new RequestMethodsRequestCondition(getRequestMethod(requestMethod));
        RequestMappingInfo mapping_info = new RequestMappingInfo(patternsRequestCondition, requestMethodsRequestCondition, null, null, null, null, null);

        requestMappingHandlerMapping.unregisterMapping(mapping_info); // 注销

注销比较简单,只需要提供requestMapingInfo对象即可。

运行效果:

1、注册api

2、请求注册的api

源码地址:https://github.com/gameloft9/api-mock-util

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值