zoukankan      html  css  js  c++  java
  • SpringMVC-HandlerMapping和HandlerAdapter

    网上介绍HandlerMapping和HandlerAdapter的文章很多,今天我用自己的理解和语言来介绍下HandlerMapping和HandlerAdapter

    一. HandlerMapping和HandlerAdapter的作用和背景:

    SpringMVC的M、V、C就不说了,HandlerMapping就是用来存放用户Request(具体可以理解为一个请求URL)和处理具体请求的Handler中的method关系的地方,例如:将/query?id=XXX的请求交给XXXService.queryById(int id)这个方法来处理。

    真正调用一个方法,首先必须找到方法定义,然后传入实参。HandlerMapping是用来映射URL和method的关系的话,HandlerAdapter是用来负责传递方法的实参。

    二. HandlerMapping和HandlerAdapter的构成:

    在Spring源码中,HandlerMapping含有HandlerExcutionChain对象,HandlerExcutionChain是由Handler和拦截器组成。有兴趣可以看下源代码,这里我仍然用自己的理解和语言来描述。

    HandlerExcutionChain你可以理解为一个对象,它是由Object(实际上就是Controller)、URL Pattern(URL的封装)和Method组成(具体对应的就是HandlerExcutionChain中的handler、interceptors),或者你可以这么理解HandlerMapping就是List<MyHandlerMapping(handler,method,url)>,URL请求交给Controller的method()来处理。

    其中handler就是SpringMVC中所有的Controller(例如:加上@Controller的类),可以循环context中所有BeanName对应的Bean,判断Bean对象是否有@Controller标签来实现。method就是Controller中具体执行请求的方法,通过循环Bean中的所有method,判断是否有@RequestMapping的value和请求的url是否匹配。url就是把Controller和method的@RequestMapping拼起来。

    HandlerAdapter是用来存放调用Controller的method时传入的形参类型,在SpringMVC中参数都是在请求URL上带入的。我们可以把HandlerAdapter理解为一个Map<HandlerMapping,paramMapping<position index,param type>>,其中HandlerMapping是用来保存请求的URL和Controller的method之间的关系,paramMapping用来保存该HandlerMapping.method的形参类型(paramMapping的key是position index,value是param type)

    // HandlerMapping源码
    public interface HandlerMapping {
        String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
        String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
        String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
        String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
        String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
        String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
    
        HandlerExecutionChain getHandler(HttpServletRequest var1) throws Exception;
    }
    
    // HandlerExcutionChain源码
    public class HandlerExecutionChain {
        private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
        private final Object handler;
        private HandlerInterceptor[] interceptors;
        private List<HandlerInterceptor> interceptorList;
        private int interceptorIndex;
    
        public HandlerExecutionChain(Object handler) {
            this(handler, (HandlerInterceptor[])null);
        }
    
        public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) {
            this.interceptorIndex = -1;
            if (handler instanceof HandlerExecutionChain) {
                HandlerExecutionChain originalChain = (HandlerExecutionChain)handler;
                this.handler = originalChain.getHandler();
                this.interceptorList = new ArrayList();
                CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
                CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
            } else {
                this.handler = handler;
                this.interceptors = interceptors;
            }
    
        }
    
        public Object getHandler() {
            return this.handler;
        }
    
        public void addInterceptor(HandlerInterceptor interceptor) {
            this.initInterceptorList().add(interceptor);
        }
    
        public void addInterceptors(HandlerInterceptor... interceptors) {
            if (!ObjectUtils.isEmpty(interceptors)) {
                CollectionUtils.mergeArrayIntoCollection(interceptors, this.initInterceptorList());
            }
    
        }
    
        private List<HandlerInterceptor> initInterceptorList() {
            if (this.interceptorList == null) {
                this.interceptorList = new ArrayList();
                if (this.interceptors != null) {
                    CollectionUtils.mergeArrayIntoCollection(this.interceptors, this.interceptorList);
                }
            }
    
            this.interceptors = null;
            return this.interceptorList;
        }
    
        public HandlerInterceptor[] getInterceptors() {
            if (this.interceptors == null && this.interceptorList != null) {
                this.interceptors = (HandlerInterceptor[])this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
            }
    
            return this.interceptors;
        }
    
        boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HandlerInterceptor[] interceptors = this.getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
                    HandlerInterceptor interceptor = interceptors[i];
                    if (!interceptor.preHandle(request, response, this.handler)) {
                        this.triggerAfterCompletion(request, response, (Exception)null);
                        return false;
                    }
                }
            }
    
            return true;
        }
    
        void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
            HandlerInterceptor[] interceptors = this.getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for(int i = interceptors.length - 1; i >= 0; --i) {
                    HandlerInterceptor interceptor = interceptors[i];
                    interceptor.postHandle(request, response, this.handler, mv);
                }
            }
    
        }
    
        void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
            HandlerInterceptor[] interceptors = this.getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for(int i = this.interceptorIndex; i >= 0; --i) {
                    HandlerInterceptor interceptor = interceptors[i];
    
                    try {
                        interceptor.afterCompletion(request, response, this.handler, ex);
                    } catch (Throwable var8) {
                        logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
                    }
                }
            }
    
        }
    
        void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
            HandlerInterceptor[] interceptors = this.getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for(int i = interceptors.length - 1; i >= 0; --i) {
                    if (interceptors[i] instanceof AsyncHandlerInterceptor) {
                        try {
                            AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor)interceptors[i];
                            asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
                        } catch (Throwable var6) {
                            logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", var6);
                        }
                    }
                }
            }
    
        }
    
        public String toString() {
            Object handler = this.getHandler();
            if (handler == null) {
                return "HandlerExecutionChain with no handler";
            } else {
                StringBuilder sb = new StringBuilder();
                sb.append("HandlerExecutionChain with handler [").append(handler).append("]");
                HandlerInterceptor[] interceptors = this.getInterceptors();
                if (!ObjectUtils.isEmpty(interceptors)) {
                    sb.append(" and ").append(interceptors.length).append(" interceptor");
                    if (interceptors.length > 1) {
                        sb.append("s");
                    }
                }
    
                return sb.toString();
            }
        }
    }

     按照自己理解写的intiHandlerMapping()方法:

    private void initHandlerMappings(ApplicationContext context) {
            //首先从容器中取到所有的实例
            String[] beanNames = context.getBeanDefinitionNames();
            try {
                for (String beanName : beanNames) {
                    Object controller = context.getBean(beanName);
                    Class<?> clazz = controller.getClass();
                    //但是不是所有的牛奶都叫特仑苏,只有带有@Controller的才处理
                    if (!clazz.isAnnotationPresent(Controller.class)) {
                        continue;
                    }
    
                    String baseUrl = "";
    
                    if (clazz.isAnnotationPresent(RequestMapping.class)) {
                        RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
                        baseUrl = requestMapping.value();
                    }
    
                    //扫描所有的public方法
                    Method[] methods = clazz.getMethods();
                    for (Method method : methods) {
                        if (!method.isAnnotationPresent(RequestMapping.class)) {
                            continue;
                        }
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                        String regex = ("/" + baseUrl + requestMapping.value().replaceAll("\*", ".*")).replaceAll("/+", "/");
                        Pattern pattern = Pattern.compile(regex);
                        this.handlerMappings.add(new HandlerMapping(pattern, controller, method));
                        System.out.println("Mapping: " + regex + " , " + method);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
  • 相关阅读:
    如何免费做一个属于自己稳定有效的图床
    关于自己每日计划是如何制定的
    记一次买4K显示器的心酸历程
    Mac常用的软件推荐
    2019 一整年的总结与一些个人反思
    Lucene学习笔记: 五,Lucene搜索过程解析
    Lucene学习笔记: 四,Lucene索引过程分析
    lucene学习笔记:三,Lucene的索引文件格式
    lucene学习笔记:二,Lucene的框架
    Lucene学习笔记:一,全文检索的基本原理
  • 原文地址:https://www.cnblogs.com/panning/p/9744708.html
Copyright © 2011-2022 走看看