SpringMVC源码阅读HandlerMapping初始化-RequestMappingHandlerMapping(六)

我们常用的使用方式就是@Contorller 和@RequsetMappig方式 就是通过RequestMappingHandlerMapping实现

类图

 

 

 AbstractHandlerMapping上一篇已经说过了 我们主要看红线框起来的

AbstractHandlerMethodMapping

实现了InitializingBean接口 spring托管初始化 就会调用这个方法

afterPropertiesSet

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet

 public void afterPropertiesSet() {
        this.initHandlerMethods();
    }

    protected void initHandlerMethods() {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Looking for request mappings in application context: " + this.getApplicationContext());
        }

        //获得容器中所有的bean的名字
        String[] beanNames = this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.obtainApplicationContext(), Object.class) : this.obtainApplicationContext().getBeanNamesForType(Object.class);
        String[] var2 = beanNames;
        int var3 = beanNames.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String beanName = var2[var4];
            //不是scopedTarget开头的
            if (!beanName.startsWith("scopedTarget.")) {
                Class beanType = null;

                try {
                    //获得bean对象对应类的class
                    beanType = this.obtainApplicationContext().getType(beanName);
                } catch (Throwable var8) {
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Could not resolve target class for bean with name '" + beanName + "'", var8);
                    }
                }
                //<1>判断是否是Handler类 比如判断是否打上了@Contorller 由子类实现注解
                if (beanType != null && this.isHandler(beanType)) {
                    //<2>解析BeeanMethods
                    this.detectHandlerMethods(beanName);
                }
            }
        }
        //空实现 传入解析号的HandleMethods
        this.handlerMethodsInitialized(this.getHandlerMethods());
    }

<1>isHandler

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#isHandler

  protected boolean isHandler(Class<?> beanType) {
        //是否打上了Controller 注解 或者是否打上了RequestMapping  如果父类打上了也会被扫描到 比如Controller打的@Service注解 父类打的@Controller
        return AnnotationUtils.findAnnotation(beanType, Controller.class) != null || AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null;
    }

<2>detectHandlerMethods

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#detectHandlerMethods

    protected void detectHandlerMethods(Object handler) {
        //如果是传入的beanname则从容器里面获得指定bean的Type如果是对象 则直接获取classs
        Class<?> handlerType = handler instanceof String ? this.obtainApplicationContext().getType((String)handler) : handler.getClass();
        if (handlerType != null) {
            //暂时不造干嘛 正常情况是=handlerType
            Class<?> userType = ClassUtils.getUserClass(handlerType);
            /**
             * 这里会遍历获取class的公共的方法 如果 是重写的父类方法 则获取父类的method
             * 筛选查打上了@RequstMapping的方法
             */
            Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (method) -> {
                try {
                    /**
                     * <3>这里this 是AbstractHandlerMethodMapping   getMappingForMethod是抽象方法由子类实现主要用于判断是否是打上了@RequestMapping的方法
                     * 并封装成RequestMappingInfo 封装了完整路由信息 如:/user/login
                     * 如果不死 则返回null
                     */
                    return this.getMappingForMethod(method, userType);
                } catch (Throwable var4) {
                    throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, var4);
                }
            });
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Mapped " + methods.size() + " handler method(s) for " + userType + ": " + methods);
            }

            methods.forEach((method, mapping) -> {
<4> Method invocableMethod
= AopUtils.selectInvocableMethod(method, userType); /** * <5>注册到mappingRegistry invocableMethod为方法 mapping为完整路由信息 */ this.registerHandlerMethod(handler, invocableMethod, mapping); }); } }

到这里mappingRegistry 就封装了所有handler和路由信息

RequestMappingHandlerMapping

<3>getMappingForMethod

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#detectHandlerMethods

->

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#getMappingForMethod

 protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        //<6>获取方法上的@RequstMapping注解并封装成RequestMappingInfo
        RequestMappingInfo info = this.createRequestMappingInfo(method);
        if (info != null) {
            //<6>这里就是对应获取Contorller上面的@RequstMapping注解
            RequestMappingInfo typeInfo = this.createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                //这里主要是2个info合并成一个 就是url拼接 controler的RequstMapping注解和方法的@RequestMapping注解拼接
                info = typeInfo.combine(info);
            }
            /**
             *  private Map<String, Predicate<Class<?>>> pathPrefixes = new LinkedHashMap();
             *  这里是利用成员变量 判断是否给此handlerType 加上指定前缀 没发现杂用
             */
          
            String prefix = this.getPathPrefix(handlerType);
            //如果有配置加上前缀
            if (prefix != null) {
                info = RequestMappingInfo.paths(new String[]{prefix}).build().combine(info);
            }
        }

        return info;
    }

<6>createRequestMappingInfo

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#detectHandlerMethods

->

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#getMappingForMethod

->

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#createRequestMappingInfo(java.lang.reflect.AnnotatedElement)

  @Nullable
    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        //获得requestMapping注解对象
        RequestMapping requestMapping = (RequestMapping) AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
        RequestCondition<?> condition = element instanceof Class ? this.getCustomTypeCondition((Class)element) : this.getCustomMethodCondition((Method)element);
        //封装成RequestMappingInfo
        return requestMapping != null ? this.createRequestMappingInfo(requestMapping, condition) : null;
    }

<5>registerHandlerMethod

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#detectHandlerMethods

->

org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod

 protected void registerHandlerMethod(Object handler, Method method, T mapping) {
        this.mappingRegistry.register(mapping, handler, method);
    }
    public void register(T mapping, Object handler, Method method) {
        //ReentrantReadWriteLock 写锁
        this.readWriteLock.writeLock().lock();

        try {
            //将handler 和method封装为HandlerMethod  内部维护了控制器 控制器方法  参数等信息
            HandlerMethod handlerMethod = AbstractHandlerMethodMapping.this.createHandlerMethod(handler, method);
            this.assertUniqueMethodMapping(handlerMethod, mapping);
            this.mappingLookup.put(mapping, handlerMethod);
            List<String> directUrls = this.getDirectUrls(mapping);
            Iterator var6 = directUrls.iterator();

            while(var6.hasNext()) {
                String url = (String)var6.next();
                //url为路由url  mapping为RequestMapppingInfo
                this.urlLookup.add(url, mapping);
            }

            String name = null;
            if (AbstractHandlerMethodMapping.this.getNamingStrategy() != null) {
                name = AbstractHandlerMethodMapping.this.getNamingStrategy().getName(handlerMethod, mapping);
                this.addMappingName(name, handlerMethod);
            }

            CorsConfiguration corsConfig = AbstractHandlerMethodMapping.this.initCorsConfiguration(handler, method, mapping);
            if (corsConfig != null) {
                this.corsLookup.put(handlerMethod, corsConfig);
            }
            /**
             * key为Mapping info 存储路由信息
             * value为MappingRegistration  内部封装了HandlerMethod和mappingInfo
             */
            this.registry.put(mapping, new AbstractHandlerMethodMapping.MappingRegistration(mapping, handlerMethod, directUrls, name));
        } finally {
            this.readWriteLock.writeLock().unlock();
        }

    }

总结

1.我们常用的注解配置是通过实现spring 的InitializingBean接口进行初始化

2.会活动容器里面所有的bean 3.判断是Handle(是否打上了@Contorller注解)

3.遍历这些Handle所有的方法遍历是否是方法Handle(是否打上了@RequestMapping)

4封装成HandleMappingInfo返回 保存了路由信息

5.最终会解析成HandleMethod保存起来 保存了控制器信息 方法信息 对象工厂信息 通过HandleMappingInfo为key  HandleMethod为Value保存起来

6.后续就可以快速找到对一个的Handle处理

posted @ 2020-01-20 15:04  意犹未尽  阅读(428)  评论(0编辑  收藏  举报