springMVC源码探索之RequestMappingHandlerMapping

本文介绍了SpringMVC中RequestMappingHandlerMapping类的作用,它是根据@Controller注解生成RequestMappingInfo的关键。详细讨论了detectHandlerMethods、afterPropertiesSet、isHandler、getMappingForMethod和createRequestMappingInfo等方法的功能,揭示了SpringMVC路径映射的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

RequestMappingHandlerMapping是AbstractHandlerMethodMapping 抽象类的唯一实现类,它的作用 是根据在Controller中的@RequestMapping注解生成RequestMappingInfo。

方法

AbstractHandlerMethodMapping是抽象类这些方法的具体实现都在子类RequestMappingHandlerMapping 中。

detectHandlerMethods

AbstractHandlerMethodMapping#detectHandlerMethods() 这个方法的作用是从handler中获取handler method并注册。detectHandlerMethods 有些方法是需要RequestMappingHandlerMapping 实现的,相关方法会在下面介绍。

/**
 * Look for handler methods in a handler.
 * @param handler the bean name of a handler or a handler instance
 */
protected void detectHandlerMethods(final Object handler) {
        Class<?> handlerType = (handler instanceof String ?
                        obtainApplicationContext().getType((String) handler) : handler.getClass());

        if (handlerType != null) {
                //为给定的类返回用户定义的类:通常只是给定的类,如果是cglib生成的子类,则返回原始的类。
                final Class<?> userType = ClassUtils.getUserClass(handlerType);
                Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                                (MethodIntrospector.MetadataLookup<T>) method -> {
                                        try {
                                                // 为处理程序方法提供映射
                                                return getMappingForMethod(method, userType);
                                        }
                                        catch (Throwable ex) {
                                                throw new IllegalStateException("Invalid mapping on handler class [" +
                                                                userType.getName() + "]: " + method, ex);
                                        }
                                });
                if (logger.isDebugEnabled()) {
                        logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
                }

                // 为查找到的handler method 进行注册
                methods.forEach((method, mapping) -> {
                        Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
                        registerHandlerMethod(handler, invocableMethod, mapping);
                });
        }
}
复制代码

afterPropertiesSet

初始化bean是调用的方法,各种配置设置并调用父类afterPropertiesSet 方法。

@Override
public void afterPropertiesSet() {
// 各种配置设置
        this.config = new RequestMappingInfo.BuilderConfiguration();
        this.config.setUrlPathHelper(getUrlPathHelper());
        this.config.setPathMatcher(getPathMatcher());
        this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
        this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
        this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
        this.config.setContentNegotiationManager(getContentNegotiationManager());
        // 调用AbstractHandlerMethodMapping afterPropertiesSet 方法
        super.afterPropertiesSet();
}
复制代码

isHandler

isHandler 方法作用是判断提供的handler是否有@Controller或@RequestMapping注解

/**
	 * {@inheritDoc}
	 * <p>Expects a handler to have either a type-level @{@link Controller}
	 * annotation or a type-level @{@link RequestMapping} annotation.
	 */
	@Override
	protected boolean isHandler(Class<?> beanType) {
		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
	}
复制代码

getMappingForMethod

通过@RequestMapping 注解生成一个RequestMappingInfo 对象并返回,如果没有使用RequestMapping 注解会返回null,主要还是看createRequestMappingInfo 方法

@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
                RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
                if (typeInfo != null) {
                        info = typeInfo.combine(info);
                }
        }
        return info;
}
复制代码

createRequestMappingInfo

createRequestMappingInfo 解析RequestMapping 注解 生成RequestMappingInfo对象。 createRequestMappingInfo(AnnotatedElement element)这个方法会先判断参数类型,然后根据类型去查找是否有额外的请求条件,如果有就把条件RequestMapping 和 条件做为参数调用重载方法 createRequestMappingInfo(RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition);

private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
    RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
    // getCustomTypeCondition 和 getCustomMethodCondition return null 
    RequestCondition<?> condition = (element instanceof Class ?
                    getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
    return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
复制代码

getCustomTypeCondition和getCustomMethodCondition 这两个方法没有实现,它们的作用是自定义请求参数条件,如果需要可以继承AbstractRequestCondition 和使用CompositeRequestCondition 类来提供多个自定义条件。

重载方法createRequestMappingInfo,实际生成RequestMappingInfo 的方法,

/**
 * Create a {@link RequestMappingInfo} from the supplied
 * {@link RequestMapping @RequestMapping} annotation, which is either
 * a directly declared annotation, a meta-annotation, or the synthesized
 * result of merging annotation attributes within an annotation hierarchy.
 */
protected RequestMappingInfo createRequestMappingInfo(
                RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

        RequestMappingInfo.Builder builder = RequestMappingInfo
                        .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
                        .methods(requestMapping.method())
                        .params(requestMapping.params())
                        .headers(requestMapping.headers())
                        .consumes(requestMapping.consumes())
                        .produces(requestMapping.produces())
                        .mappingName(requestMapping.name());
        if (customCondition != null) {
                builder.customCondition(customCondition);
        }
        return builder.options(this.config).build();
}
复制代码

上面就是简单的介绍了一下springmvc路径映射过程,有兴趣的还是看下源码吧,

能力有限,水平一般,如有错误,请多指出。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值