Spring源码学习篇6 - DispatcherServlet 基本工作流程

配置DispatcherServlet

Servlet3.0之后, Servlet可以被动态监测到,web.xml不再是必须的,一般的servlet可以使用@WebServlet,除了添加注解,也可编程配置。WebApplicationInitializer的实现类在应用部署的时候会被执行,可以再WebApplicationInitializer.onStartup中配置Spring的DispatcherServlet

public class MyWebApplicationInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext webApplicationContext = new AnnotationConfigWebApplicationContext();
        webApplicationContext.register(AppConfig.class);

        DispatcherServlet dispatcherServlet = new DispatcherServlet(webApplicationContext);
        ServletRegistration.Dynamic registration = servletContext.addServlet("springApp", dispatcherServlet);
        registration.setLoadOnStartup(1);
        registration.addMapping("/app/*");
    }
}

WebApplicationInitializer会被执行的原因是,从servlet3.0之后,Servlet容器会根据SPI机制,在Spring-web模块下的MATE-INF/services/javax.servlet.ServletContainerInitializer文件中,找到ServletContainerInitializer具体实现类:

//文件:MATE-INF/services/javax.servlet.ServletContainerInitializer
org.springframework.web.SpringServletContainerInitializer

ServletContainerInitializer只有一个方法,第一个参数将会是HandlesTypes注解声明将会处理的类型;在Spring中实现类就是SpringServletContainerInitializer,HandlesTypes声明的类型是WebApplicationInitializer, 所以在应用初始化的时候WebApplicationInitializer的实现类将会被执行,可以在其中配置servlet、filter等等。

public interface ServletContainerInitializer {
    public void onStartup(Set<Class<?>> c, ServletContext ctx)
        throws ServletException; 
}

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
		@Override
	public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {
		List<WebApplicationInitializer> initializers = Collections.emptyList();
		// ... 省略部分:
		// 主要内容是:将webAppInitializerClasses中非接口和非抽象类的实例化后,添加到initializers
		AnnotationAwareOrderComparator.sort(initializers);
		for (WebApplicationInitializer initializer : initializers) {
			initializer.onStartup(servletContext);
		}
	}
}

可以配置多个DispatcherServlet,每个Servlet有自己专属的Servlet WebApplicationContext, 它的parent将会是Root WebAppcalitionContext。通过这种方式,可以将公共的services等bean配置在ROOT中;

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { RootConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { App1Config.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/app1/*" };
    }
}

DispatcherServlet 的初始化

init是Servlet生命周期的开始,对DispatcherServlet来说,配置webApplicationContext并初始Bean都在其中。org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext中包含主要的两部分逻辑:

  1. org.springframework.web.servlet.FrameworkServlet#configureAndRefreshWebApplicationContext
  2. org.springframework.web.servlet.DispatcherServlet#initStrategies
初始化基础Bean

这部分,除了ApplicationContext上记录了servlet相关的信息之外,创建Bean的逻辑与之前了解到的没有什么不同,这里目前还不包含对Controller的处理。

wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
	((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}

postProcessWebApplicationContext(wac);
applyInitializers(wac);
wac.refresh();
Servlet处理请求用的相关Bean
protected void initStrategies(ApplicationContext context) {
	initMultipartResolver(context);
	initLocaleResolver(context);
	initThemeResolver(context);
	initHandlerMappings(context);
	initHandlerAdapters(context);
	initHandlerExceptionResolvers(context);
	initRequestToViewNameTranslator(context);
	initViewResolvers(context);
	initFlashMapManager(context);
}

这里先主要关心Controller 以及RestContoller的工作流程,这里HandlerMapping是非常重要的,如果没有配置自己的HandlerMapping的话,将会从DispatcherServlet.properties读取默认的实现类:

org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.function.support.RouterFunctionMapping

读取到这些类并实例化为Spring中的Bean,这些类都实现了afterPropertiesSet。以RequestMappingHandlerMapping为例:

// AbstractHandlerMethodMapping.java
public void afterPropertiesSet() {
	initHandlerMethods();
}

/**
 * Scan beans in the ApplicationContext, detect and register handler methods.
 * @see #getCandidateBeanNames()
 * @see #processCandidateBean
 * @see #handlerMethodsInitialized
 */
protected void initHandlerMethods() {
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
			processCandidateBean(beanName);
		}
	}
	handlerMethodsInitialized(getHandlerMethods());
}

protected void processCandidateBean(String beanName) {
	Class<?> beanType = null;
	try {
		beanType = obtainApplicationContext().getType(beanName);
	}
	catch (Throwable ex) {
		// An unresolvable bean type, probably from a lazy bean - let's ignore it.
		if (logger.isTraceEnabled()) {
			logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
		}
	}
	if (beanType != null && isHandler(beanType)) {
		detectHandlerMethods(beanName);
	}
}

@Override
protected boolean isHandler(Class<?> beanType) {
	return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
			AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

可以看会对所有的Bean进行处理,如果Bean含有Controller或者RequestMapping注解,那么对所有的 RequestMapping注解的方法进行处理:

  1. 根据@RequestMapping注解,构造RequestMappingInfo
    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();
    }
    
  2. 构造HandlerMethod,它主要包含两个重要属性:bean 以及对应的含有@RequestMapping的Method
  3. 获取DirectPath, 并记录DirectPath与RequestMappingInfo的关联
  4. 记录方法名,与HandlerMethod对象的关联
  5. 记录 handlerMethod 与 CorsConfiguration配置对象的关联
  6. 记录RequestMappingInfo 与 MappingRegistratio对象的关联
    //MappingRegistration
    public MappingRegistration(T mapping, HandlerMethod handlerMethod,
    	@Nullable Set<String> directPaths, @Nullable String mappingName, boolean corsConfig) {
    
    Assert.notNull(mapping, "Mapping must not be null");
    Assert.notNull(handlerMethod, "HandlerMethod must not be null");
    this.mapping = mapping;
    this.handlerMethod = handlerMethod;
    this.directPaths = (directPaths != null ? directPaths : Collections.emptySet());
    this.mappingName = mappingName;
    this.corsConfig = corsConfig;
    }
    

处理请求

当客户端发起请求的时候,如果满足DispatcherServlet的处理路径,那么经过doService,交由doDispatch进行处理请求,主要处理逻辑如下:

processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
	noHandlerFound(processedRequest, response);
	return;
}

// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
	long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
	if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
		return;
	}
}

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
	return;
}

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
	return;
}

applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
大致的处理流程如下

第一步是根据请求,获取对应的HandlerMethod

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	String lookupPath = initLookupPath(request);
	this.mappingRegistry.acquireReadLock();
	try {
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		this.mappingRegistry.releaseReadLock();
	}
}

基本流程是获取到请求的path, 然后得到RequestMappingInfo,最后取得HandlerMethod

第二步,是构造HandlerExecutionChain,主要是添加合适的拦截器

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
	HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
			(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

	for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
		if (interceptor instanceof MappedInterceptor) {
			MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
			if (mappedInterceptor.matches(request)) {
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}
		else {
			chain.addInterceptor(interceptor);
		}
	}
	return chain;
}

第三步,处理CorsConfiguration

protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
		HandlerExecutionChain chain, @Nullable CorsConfiguration config) {

	if (CorsUtils.isPreFlightRequest(request)) {
		HandlerInterceptor[] interceptors = chain.getInterceptors();
		return new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
	}
	else {
		chain.addInterceptor(0, new CorsInterceptor(config));
		return chain;
	}
}

第四步,确定HandlerAdapter,各个adapter是否可以处理当前handler的判断也比较简单,比如AbstractHandlerMethodAdapter 基本只要handler是HandlerMethod实例可以。

// AbstractHandlerMethodAdapter.java
@Override
public final boolean supports(Object handler) {
	return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

第五步,优先调用各拦截器的preHandle方法,如果有个拦截器返回false,那么结束处理

第六步,通过HandlerAdapter的实例调用具体的bean,像RequestMappingHandlerAdapter.handleInternal,并得到ModelAndView

第七步,调用各拦截器的postHandle方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值