springmvc整合springboot执行流程---源码分析

        本文介绍springmvc被springboot整合之后,web容器注册spring容器,初始化DispatcherServlet,controller里面的方法注册,访问过程。

首先从springboot-autoconfigure包下面的META-INF/spring-factories里面找到WebMvcAutoConfiguration这个自动配置类,在209行会看到RequestMappingHandlerMapping这个类被创建成bean,这个类有个afterPropertiesSet()方法,在spring容器初始化就会调用这个方法,这个方法用来处理所有标记有@controller的注解的类,并找出所有标记@RequestMapping注解的方法,存到HandlerMethod类里。等第一次访问时就走DispathServlet的init初始化流程

 

注册类 

部分代码

在spring-factories文件里会找到DispatcherServletAutoConfiguration和WebMvcAutoConfiguration,其他的类那你也可以自己打开看看,断点调试。

spring.factories文件中部分代码

org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\

进入DispatcherServletAutoConfiguration类打断点可以看到图,这里会注册一个dispatchServlet,拦截路径是   /   。后面访问的时候会进入初始化方法init()。

 断点进入AbstractHandlerMethodMapping类

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

	/**
	 * Scan beans in the ApplicationContext, detect and register handler methods.
	 * @see #getCandidateBeanNames()
	 * @see #processCandidateBean
	 * @see #handlerMethodsInitialized
	 */
	protected void initHandlerMethods() {
    // 获取spring容器中所有的bean,进行处理
		for (String beanName : getCandidateBeanNames()) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
        //处理bean的方法,会进行过滤
				processCandidateBean(beanName);
			}
		}
// 空方法
		handlerMethodsInitialized(getHandlerMethods());
	}

看截图

 这里会进入发现处理的方法。看判断的isHandler(beanType)这个方法,这里进行过滤

@Override
	protected boolean isHandler(Class<?> beanType) {
		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
	}
protected void detectHandlerMethods(Object handler) {
		Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());

		if (handlerType != null) {
			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.isTraceEnabled()) {
				logger.trace(formatMappings(userType, methods));
			}
			else if (mappingsLogger.isDebugEnabled()) {
				mappingsLogger.debug(formatMappings(userType, methods));
			}
			methods.forEach((method, mapping) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
        // 注册方法到map中
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}
	}

注册方法AbstractHandlerMethodMapping这个类中

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
		this.mappingRegistry.register(mapping, handler, method);
	}

注册

public void register(T mapping, Object handler, Method method) {
			this.readWriteLock.writeLock().lock();
			try {
// 创建方法类
				HandlerMethod handlerMethod = createHandlerMethod(handler, method);
//校验是否已经存在
				validateMethodMapping(handlerMethod, mapping);

				Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
				for (String path : directPaths) {
					this.pathLookup.add(path, mapping);
				}

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

				CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
				if (corsConfig != null) {
					corsConfig.validateAllowCredentials();
					this.corsLookup.put(handlerMethod, corsConfig);
				}
// 注册到map中,以后拿处理器映射器从这里找
				this.registry.put(mapping,
						new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
			}
			finally {
				this.readWriteLock.writeLock().unlock();
			}
		}

页面访问任意路径:

        因为dispatchServlet是一个servlet,所以第一次访问的时候会进行初始化,首先访问的是HttpServletBean类中的init方法,具体类结构看下图。再访问frameWorkServlet中的initServletBean方法。会初始化initWebApplicationContext();和initFrameworkServlet();完成初始化

图1 类结构图

 

图2  初始化方法

 

初始化完成之后,进入FrameWorkServlet类中的doPost...方法,再进入processRequest(request, response);这个方法,最后会进入DispatchServlet中的doService()设置一些属性之后,进入doDispatch(request, response);这个方法,进行查找处理器映射器HandlerExecutionChainmappedHandler = getHandler(processedRequest);

再查找处理器适配器HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

 再找到视图

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

处理返回结果

最后进入

mappedHandler.triggerAfterCompletion(request, response, null);

执行拦截器的方法,如果没有自定义的,这里跳过,不执行。

        就总结这些了。。。。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值