springMVC中的@requestmapping 的原理分析。

1 代码启动类会有注解@EnableWebMvc

2 打开该注解。发现里面有代码

 

3 打开DelegatingWebMvcConfiguration 发现里面并未定义什么东西,都是一些方法。于是找其父类。WebMvcConfigurationSupport

4 WebMvcConfigurationSupport 中定义了一个bean,这里说一句,@enable**类型的启用注解,大多都是增加一个配置bean,在其初始化过程中实现自己的新增的功能。

@Bean

public RequestMappingHandlerMapping requestMappingHandlerMapping() {

RequestMappingHandlerMapping handlerMapping = createRequestMappingHandlerMapping();

handlerMapping.setOrder(0);

handlerMapping.setInterceptors(getInterceptors());

handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());

handlerMapping.setCorsConfigurations(getCorsConfigurations());



PathMatchConfigurer configurer = getPathMatchConfigurer();

if (configurer.isUseSuffixPatternMatch() != null) {

handlerMapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch().booleanValue());

}

if (configurer.isUseRegisteredSuffixPatternMatch() != null) {

handlerMapping

.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch().booleanValue());

}

if (configurer.isUseTrailingSlashMatch() != null) {

handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch().booleanValue());

}

if (configurer.getPathMatcher() != null) {

handlerMapping.setPathMatcher(configurer.getPathMatcher());

}

if (configurer.getUrlPathHelper() != null) {

handlerMapping.setUrlPathHelper(configurer.getUrlPathHelper());

}



return handlerMapping;

}

5 经过4中配置的bean 就生成了这个bean ,那生成以后如何注册到spring容器中呢?

层层往上,找到该类的父类一直跟到爷爷那一辈,发现继承了父类实现了InitializingBean,那么在初始化的时候就会调用afterPropertiesSet方法。看下父类afterPropertiesSet的实现

@Override
public void afterPropertiesSet() {
    initHandlerMethods();
}

protected void initHandlerMethods() {
    if (logger.isDebugEnabled()) {
        logger.debug("Looking for request mappings in application context: " + getApplicationContext());
    }
    //detectHandlerMethodsInAncestorContexts默认false,所以是得到所有的beanNames
    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
            BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
            getApplicationContext().getBeanNamesForType(Object.class));

    for (String beanName : beanNames) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            Class<?> beanType = null;
            try {
                beanType = getApplicationContext().getType(beanName);
            }
            catch (Throwable ex) {
                // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                if (logger.isDebugEnabled()) {
                    logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                }
            }
            //2. isHandler由子类实现
            if (beanType != null && isHandler(beanType)) {
                //3. 查找controller中有@RequestMapping注解的方法,并注册到请求
                detectHandlerMethods(beanName);
            }
        }
    }
    //空方法
    handlerMethodsInitialized(getHandlerMethods());
}

6 这个时候就要和spring-beans工程扯上关系了。目前还是不会i是很清楚,当初读源码的时候隐约记得是,实现了这个接口,就可以在bean初始化之后进行一些其他的操作。这里自己定义的afterPropertiesSet()方法。目的就很简单了,过滤所有的bean,拦截住拥有该注解的类或者bean,然后找到带有注解的方法。(方法名称叫就能看出,这个方法是在bean生成后进行处理的得,所以此时是已经有bean的了。)

7 为了实现第六步,拿到所有bean 和拦截,requestmappinghandlermapping还顺便继承了很多类和实现了很多接口,可以查看下边的 继承关系(一定要学会eclipse的快捷键F4 最好是能看UML关系,如果有幸能看到spring的UML就好了,可惜我不知道哪里有,除了别人的blog,如果有人知道,记得告诉我哦。) 。看下边的继承关系,最终实现的就是applicationcontextAware接口,这个接口的作用就是为了获取applicationcontext 的也就是spring暴露的供我们使用的bean容器。

public abstract class ApplicationObjectSupport implements ApplicationContextAware {

 

8 绕了一大堆,就是为了说明当bean初始化执行后,会执行该bean的afterPropertiesSet()方法。首先是执行的RequestMappingHandlerMapping 的,内部有调用父类AbstractHandlerMethodMapping的该方法。

 

9然后一步一步执行,将requestmapping的东西注册到一个map中

AbstractHandlerMethodMapping的内部类。

10调用的时候是dispatchservlet 默认也是用的那个RequestMappingHandlerMapping 类,所以就可以拿到里面的信息,进行匹配和调用。

11 源码中注解的过滤处理等没有仔细看。也就是java的反射的一些东西。后期会看。

12 附件中有一个自定义类似于@requestmapping的注解。请搜索 :简化版@requestmapping注解注册源码

13 参考https://www.jianshu.com/p/8d60bf614200文章,感谢作者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值