springmvc-源码调试-3.2-initHandlerMappings

前言

接着 springmvc-源码调试-3.0本文主要分析一个方法…initHandlerMappings springMVC 重中之重
HadnlerMappings 处理器映射器

需要说明的是 !! HandlerMapping 实现各有不同… 而我直接采用的 spring 源码 运行起来的,也就是说大部分为默认…

initHandlerMappings

private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    // 该值默认为 true 但是可以设置为 false
    // 如果设置为 false 那  Spring MVC就只会查找名为“handlerMapping”的bean,并作为当前系统的唯一的HandlerMapping
    // 如果是 ture 则查询所有的..
    if (this.detectAllHandlerMappings) {
        //在ApplicationContext中查找所有handler映射,包括父类上下文。
        Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        //如果不为空
        if (!matchingBeans.isEmpty()) {
            // 将获取的 HandlerMapping 转换成集合..
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // 排序
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    else {
        try {
            // 从容器中获取 HandlerMapping ,如果获取不到 下面则会添加默认的..
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }
        catch (NoSuchBeanDefinitionException ex) {
            //稍后就会创建一个默认的~~~
        }
    }
 
    //通过注册,确保至少有一个HandlerMapping
    //如果找不到其他映射,则为默认的HandlerMapping。
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
    }
 
    for (HandlerMapping mapping : this.handlerMappings) {
        if (mapping.usesPathPatterns()) {
            this.parseRequestPath = true;
            break;
        }
    }
}

getDefaultStrategies

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    if (defaultStrategies == null) {
        try {
            // 从配置文件加载默认的 简单的说 加载 DispatcherServlet.properties 这个文件...
            ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
            // 默认的策略~~~
            defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
        }
        catch (IOException ex) {
            throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
        }
    }
    //获取 org.springframework.web.servlet.HandlerMapping
    String key = strategyInterface.getName();
    // org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
    // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
    // org.springframework.web.servlet.function.support.RouterFunctionMapping
    String value = defaultStrategies.getProperty(key);
    if (value != null) {
        // 将 获取的 value 转换成数组
        String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
        List<T> strategies = new ArrayList<>(classNames.length);
        // 循环
        for (String className : classNames) {
            try {
                //  根据 路径获取 class
                Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                //  创建...
                Object strategy = createDefaultStrategy(context, clazz);
                // 添加到集合中
                strategies.add((T) strategy);
            }
            catch (ClassNotFoundException ex) {
               // 抛出异常
            }
            catch (LinkageError err) {
               // 抛出异常
            }
        }
        return strategies;
    }
    else {
        return new LinkedList<>();
    }
}
 

上面没什么可说的… 只要就是 createDefaultStrategy()会循环三次… 也就说会默认创建 HandlerMapping

  • BeanNameUrlHandlerMapping
  • RequestMappingHandlerMapping
  • RouterFunctionMapping
protected Object createDefaultStrategy(ApplicationContext context, Class<?> clazz) {
    return context.getAutowireCapableBeanFactory().createBean(clazz);
}
 
public <T> T createBean(Class<T> beanClass) throws BeansException {
    RootBeanDefinition bd = new RootBeanDefinition(beanClass);
    bd.setScope(SCOPE_PROTOTYPE);
    bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
    // 创建Bean..
    return (T) createBean(beanClass.getName(), bd, null);
}

上面的源码不过多深究了。。就是创建Bean去了

BeanNameUrlHandlerMapping

先看一下该类的接口关系…因为关系到了一些方法的初始化回调… 如果你不看你压根就不知道这个方法在啥时候执行的…

可以看到 该类还是 一个 aware 类型. 而 spring 中 通过 这些回调帮助我们设置一些内容… 也就是说 spring 会回调这三个接口中的方法…

所以还得需要知道这三个接口定义了什么…

image-20201019105216489

ApplicationContextAware:会帮我们注入 ApplicationContext

ServletContextAware: 会帮我们注 入ServletContext

BeanNameAware : 会帮我们注入 这个BeanName

那也就意味着 整个关系链中有 这三个接口的实现,从上图关系链中

AbstractHandlerMappin 实现了 BeanNameAware 看了下源码里面并没有其他的动作… 所以不必深究,主要看一下 setApplicationContext

setApplicationContext

ApplicationObjectSupport实现了 ApplicationContextAware也就说在创建对象的时候会调用setApplicationContext(ApplicationContext context)

public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
    // 由于是回调方法.. 所以 context 不可能是为null,条件不成立进入else
    if (context == null && !isContextRequired()) {
        // Reset internal context state.
        this.applicationContext = null;
        this.messageSourceAccessor = null;
    }
    else if (this.applicationContext == null) {
        // 如果传入了相同的上下文,则忽略重新初始化。
        if (!requiredContextClass().isInstance(context)) {
            throw new ApplicationContextException(
                "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
        }
        this.applicationContext = context;
        this.messageSourceAccessor = new MessageSourceAccessor(context);
        // 主要是这里....
        initApplicationContext(context);
    }
    else {
        // Ignore reinitialization if same context passed in.
        if (this.applicationContext != context) {
            throw new ApplicationContextException(
                "Cannot reinitialize with different application context: current one is [" +
                this.applicationContext + "], passed-in one is [" + context + "]");
        }
    }
}
 

initApplicationContext

如果单纯的IDEA 点方法会发现最后是一个空方法… 这个是由子类去覆盖的而我们的子类是一大坨…所以还是根据IDEA 堆栈 去看。。

可以看到 WebApplicationObjectSupport 重写了 ApplicationObjectSupport.initApplicationContext()方法…

protected void initApplicationContext(ApplicationContext context) {
    // 这里有去调用父类的.. initApplicationContext(ApplicationContext context)
    // 也就是调用 ApplicationObjectSupport.initApplicationContext()
    super.initApplicationContext(context);
    // 如果 servletContext 为空 并且 servletContext 是 WebApplicationContext类型
    if (this.servletContext == null && context instanceof WebApplicationContext) {
        // 强制获取 ServletContext
        this.servletContext = ((WebApplicationContext) context).getServletContext();
        // 如果 不是空的 则会去初始化..
        if (this.servletContext != null) {
            //  这里先不分析..
            initServletContext(this.servletContext);
        }
    }
}

ApplicationObjectSupport.initApplicationContext()这个方法是有子类调用的… 因为 子类调用的时候加了upser.initApplicationContext()

protected void initApplicationContext(ApplicationContext context) throws BeansException {
    // 继续调用.. 由于当前类是 BeanNameUrlHandlerMapping ,
    // 所以会调用 BeanNameUrlHandlerMapping里面的 initApplicationContext 如果没有则会调用父类.. 如果父类没有则会调用父类的父类.
    // 如果都没有 则会调用 空实现..
    // 而这里则有 AbstractDetectingUrlHandlerMapping 去重写了..所以调用的是 AbstractDetectingUrlHandlerMapping
    initApplicationContext();
}

AbstractDetectingUrlHandlerMapping.initApplicationContext()

public void initApplicationContext() throws ApplicationContextException {
    //这里由去调用父类..走到这里我人傻了......
    super.initApplicationContext();
    detectHandlers();
}

initApplicationContext()

AbstractHandlerMapping.initApplicationContext()

protected void initApplicationContext() throws BeansException {
    // 里面是一个空实现..
    extendInterceptors(this.interceptors);
    // 获取所有的 MappedInterceptor 并且放入到 List(adaptedInterceptors)集合
    // 简单来说就是根据 MappedInterceptor 获取其所有的 子类.
    detectMappedInterceptors(this.adaptedInterceptors);
    // 初始化拦截器..
    initInterceptors();
}

detectHandlers()

protected void detectHandlers() throws BeansException {
    // 获取 ApplicationContext
    ApplicationContext applicationContext = obtainApplicationContext();
    // 获取容器中所有的 beanName
    String[] beanNames = (this.detectHandlersInAncestorContexts ?
                          BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
                          applicationContext.getBeanNamesForType(Object.class));
 
    // Take any bean name that we can determine URLs for.
    for (String beanName : beanNames) {
        String[] urls = determineUrlsForHandler(beanName);
        if (!ObjectUtils.isEmpty(urls)) {
            // URL paths found: Let's consider it a handler.
            registerHandler(urls, beanName);
        }
    }
 
    if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {
        logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());
    }
}

多态搞死人,大致调用链…

image-20201019113848393

在看一下继承链主要怕你们绕晕…

image-20201019113928158

RequestMappingHandlerMapping

image-20201019155353515

主要分析 InitializingBean,如果对该接口不太熟悉的… 可以去了解一下.这里简单说一下

简单说实现 InitializingBean 接口 里面有一个方法,其作用就是在初始化的时候做一个回调,比如@PostConstruct这个注解总知道吧…同理…

这里不分析 ApplicationContextAware,是因为跟 BeanNameUrlHandlerMapping 没啥区别… 没做什么特别的事情…

afterPropertiesSet()

RequestMappingHandlerMapping.afterPropertiesSet();

public void afterPropertiesSet() {
    // 创建 BuilderConfiguration
    this.config = new RequestMappingInfo.BuilderConfiguration();
    this.config.setTrailingSlashMatch(useTrailingSlashMatch());
    this.config.setContentNegotiationManager(getContentNegotiationManager());
 
    if (getPatternParser() != null) {
        this.config.setPatternParser(getPatternParser());
        Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch,
                      "Suffix pattern matching not supported with PathPatternParser.");
    }
    else {
        this.config.setSuffixPatternMatch(useSuffixPatternMatch());
        this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
        this.config.setPathMatcher(getPathMatcher());
    }
 
    super.afterPropertiesSet();
}

afterPropertiesSet();

AbstractHandlerMethodMapping.afterPropertiesSet()

public void afterPropertiesSet() {
    initHandlerMethods();
}

initHandlerMethods()

初始化 HandlerMethods

protected void initHandlerMethods() {
    // 获取所有的 BeanNames
    for (String beanName : getCandidateBeanNames()) {
        // 判断不是已 scopedTarget 开头
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            processCandidateBean(beanName);
        }
    }
    handlerMethodsInitialized(getHandlerMethods());
}

processCandidateBean

protected void processCandidateBean(String beanName) {
    Class<?> beanType = null;
    try {
        // 获取具体的类型.
        beanType = obtainApplicationContext().getType(beanName);
    }
    catch (Throwable ex) {
        // 一个无法解析的bean类型,可能来自一个lazy bean-让我们忽略它。
        // 日志打印...
    }
    // 不是null 并且 类型是存在 @Controller 或者 @RequestMapping  注解
    if (beanType != null && isHandler(beanType)) {
        detectHandlerMethods(beanName);
    }
}
isHandler
protected boolean isHandler(Class<?> beanType) {
    // 存在 Controller注解 或者存在 RequestMapping 注解 ..
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
            AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
detectHandlerMethods
protected void detectHandlerMethods(Object handler) {
	    // 如果传递是 String 则 获取其类型 ,如果是是class 则直接返回
		Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());
		if (handlerType != null) {
		    // 获取用户 class 而非 代理类 或者Object.class
			Class<?> userType = ClassUtils.getUserClass(handlerType);
			// 传递 Class 对这个 Class 所有方法进行校验..
			Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> {
						try {
						    // 里面主要是  获取 方法 和类上的 @RequestMapping 将其合并.
                            // 如果没有的话则会返回 null,而由于是 lambda 这里主要是制订过滤规则
                            // 如果返回了 null 则 selectMethods 不会将其放入到Map中。
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
					});
			//循环所有
			methods.forEach((method, mapping) -> {
                //再次核查方法与类型是否匹配
                Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                // 如果是满足要求的方法,则注册到全局的MappingRegistry实例里
                registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}

以上所有的代码就是去处理 @RequestMapping

RouterFunctionMapping

RequestMappingHandlerMapping 的继承体系差不多…这里就不贴图了…

主要分析 InitializingBean,如果对该接口不太熟悉的… 可以去了解一下.这里简单说一下

简单说实现 InitializingBean 接口 里面有一个方法,其作用就是在初始化的时候做一个回调,比如@PostConstruct这个注解总知道吧…同理…

afterPropertiesSet

public void afterPropertiesSet() throws Exception {
    if (this.routerFunction == null) {
        // 这里不深究了 .. 这里是处理  RouterFunction 
        initRouterFunction();
    }
    // 如果 消息转换器  为空的 话初始化
    if (CollectionUtils.isEmpty(this.messageConverters)) {
        initMessageConverters();
    }
}

initMessageConverters

主要添加了4个转换器…

private void initMessageConverters() {
    List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(4);

    messageConverters.add(new ByteArrayHttpMessageConverter());
    messageConverters.add(new StringHttpMessageConverter());

    if (!shouldIgnoreXml) {
        try {
            messageConverters.add(new SourceHttpMessageConverter<>());
        }
        catch (Error err) {
            // Ignore when no TransformerFactory implementation is available
        }
    }
    messageConverters.add(new AllEncompassingFormHttpMessageConverter());

    this.messageConverters = messageConverters;
}

后言

这里简单将一下 几个回调…

首先ApplicationContextAware 就是你实现这个借口会有一个回调… 如何做的呢?

  1. spring 去创建这个Bean的时候,注册了ApplicationContextAwareProcessor
  2. 在每一个对象创建的时候 都会走 ApplicationContextAwareProcessor .postProcessBeforeInitialization 方法
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 看到了吧 这里 判断你是不是 这个类型的... 
        // 而我们的上面三个类都是实现了 ApplicationContextAware 接口..
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
			return bean;
		}

		AccessControlContext acc = null;

		if (System.getSecurityManager() != null) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
            // 这里是去进行回调去了..
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

invokeAwareInterfaces:一顿瞎几把判断… 然后转换执行即可…

	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}

后后言

如有问题欢迎指导交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值