springmvc 源码分析(三) -- 自定义处理器映射器和自定义处理器适配器,以及自定义参数解析器

时间:2020-07-04 16:13:50   收藏:0   阅读:297

 测试环境搭建: 本次搭建是基于springboot来实现的,代码在码云的链接:https://gitee.com/yangxioahui/thymeleaf.git

  DispatcherServlet核心流程在上一篇源码分析已经做了详细讲解 了,参考: https://www.cnblogs.com/yangxiaohui227/p/13229413.html 

1. 自定义处理器映射器和处理器适配器:

本次目标是使得我自定义的controller生效

技术分享图片

 技术分享图片

 

  技术分享图片

 

 //自定义映射器,使得springmvc 可以通过/test22 找到我的MyTestController

@Component
public class MyHandlerMapping implements HandlerMapping, ApplicationContextAware, Ordered {
    private ApplicationContext  applicationContext;

    private Map<String,Object> handlerMap=new HashMap<>();  //spring 在启动时,会将所有被我的@MyRequestMapping注解标注的bean 存到这里,例如我们定义的MyTestController

    @Override
    public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        String requestURI = request.getRequestURI(); //从请求参数中拿到对应的url
        Object o = handlerMap.get(requestURI); //通过url或者handler
        if(null!=o){
            HandlerExecutionChain handlerExecutionChain = new HandlerExecutionChain(o);
            return handlerExecutionChain;
        }
        return null;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
        this.detectHandler(applicationContext); //spring 容器创建该bean时会回调该方法

    }

    private void detectHandler(ApplicationContext applicationContext) {
        //获取所有的BeanName
        String[] definitionNames = applicationContext.getBeanDefinitionNames(); 
        for (String beanName : definitionNames) {
            //获取对应的bean
            Object bean = applicationContext.getBean(beanName);
            //判断是否贴有我们要的注解
            MyRequestMapping annotation = bean.getClass().getAnnotation(MyRequestMapping.class);
            if(null!=annotation){
                String url = annotation.url();
                handlerMap.put(url,bean);
            }
        }
    }

    @Override
    public int getOrder() {  //因为springmvc 中有很多HandlerMapping,只要其中一个匹配到对应的url,就会返回,所以我们要将这里的优先级设置最高
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

 

 自定义适配器:

@Component
public class MyHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return handler instanceof ModlerInterface; //我们定义的适配器,处理的类型就是ModlerInterface
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        ModlerInterface modlerInterface=(ModlerInterface)handler;
         modlerInterface.doHandler(request, response); //直接调用目标方法
        return null;
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        return 0;
    }
}

 

 浏览器调用:

技术分享图片

 

 原理分析:

 自定义映射器和自定义适配器添加到DispatcherServlet原理:

DispatcherServlet 的List<HandlerMapping> handlerMappings 初始化方法:

技术分享图片

 

 DispatcherServlet的List<HandlerAdapter> handlerAdapters 的原理同上;

我们再debug调试下自定义HandlerMapping的过程: 

启动项目:

技术分享图片

 

 

 技术分享图片

 

 浏览器debug 调用我们的目标方法:

技术分享图片

 

 技术分享图片

 

 技术分享图片

 

 技术分享图片

 

 技术分享图片

 

 技术分享图片

 

 这样就找到我们的适配器了,之后通过适配器调用目标方法:

技术分享图片

 

 技术分享图片

 

 技术分享图片

 

 



 

原文:https://www.cnblogs.com/yangxiaohui227/p/13235038.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!