springmvc path请求映射到bean 方法的流程

网友投稿 279 2022-12-25

springmvc path请求映射到bean 方法的流程

一、加载注册流程

1.在dispatch-servlet.xml中配置< mvc:annotation-driven/>,在控制器的方法上加入@RequestMapping注解即可。

2.mvc:annotation-driven的解析流程 会调用到自定义元素解析器的AnnotationDrivenBeanDefinitionParser.parse方法。

3.org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping为RequestMapping注解映射到后台接口的注册表。此类实现了InitializingBean接口,会触发到

afterPropertiesSet方法。

org.springframework.web.servlet.handler.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() {

for (String beanName : getCandidateBeanNames()) {

if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {

processCandidateBean(beanName);

}

}

handlerMethodsInitialized(getHandlerMethods());

}

4.在initHandlerMethods方法中会先调用getCandidateBeanNames获取当前容器工厂的所有BEAN,然后逐个BEAN进行处理。

4.1 获取所有BEAN流程

protected String[] getCandidateBeanNames() {

return (this.detectHandlerMethodsInAncestorContexts ?

BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :

obtainApplicationContext().getBeanNamesForType(Object.class));

}

4.2 处理BEAN流程

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);

}

}

4.3 判断当前BEAN是否HANDLER

protected boolean isHandler(Class> beanType) {

return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||

AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));

}

4.4 如果此类是控制器或者有requestMapping注解,才会处理。

4.5 遍历当前类的所有方法,查找包含RequestMapping注解的方法,然后保存到

AbstractHandlerMethodMapping.MappingRegistry注册表中。

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 methods = MethodIntrospector.selectMethods(userType,

(MethodIntrospector.MetadataLookup) 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));

}

methods.forEach((method, mapping) -> {

Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);

registerHandlerMethod(handler, invocableMethod, mapping);

});

}

}

判断当前方法是否包含requestMapping注解

private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {

RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);

RequestCondition> condition = (element instanceof Class ?

getCustomTypeCondition((Class>) element) : getCustomMethodCondition((Method) element));

return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);

}

最终会调用org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod保存到URL和RequestMappinfo的映射注册表中。

AbstractHandlerMethodMapping

protected void registerHandlerMethod(Object handler, Method method, T mapping) {

this.mappingRegistry.register(mapping, handler, method);

}

具体的保存逻辑

在这个方法中主要操作的数据对象有四个,分别是mappingLookup、urlLookup、corsLookup和registry。下面对这四个对象进行说明:

mappingLookup对象是Map结构,key表示mapping对象,value表示处理对象,在本例中key是RequestMappingInfo对象,value是Controller中的某一个方法。

urlLookup对象是Map结构,key表示url,value表示mapping对象,本例中key是具体的url值"/demo/postMapping/",value是RequestMappingInfo对象,

corsLookup对象是Map结构,key表示处理方法(Controller中的某个方法),value表示跨域配置,本例中没有进行跨域注解的使用因此数据不存在,如果需要看到跨域数据,可以在method上添加@CrossOrigin注解

registry对象是Map结构,key表示mapping对象,value表示MappingRegistration对象

AbstractHandlerMethodMapping.MappingRegistry 内部类

public void register(T mapping, Object handler, Method method) {

this.readWriteLock.writeLock().lock();

try {

HandlerMethod handlerMethod = createHandlerMethod(handler, method);

validateMethodMapping(handlerMethod, mapping);

this.mappingLookup.put(mapping, handlerMethod);

List directUrls = getDirectUrls(mapping);

for (String url : directUrls) {

this.urlLookup.add(url, mapping);

}

String name = null;

if (getNamingStrategy() != null) {

name = getNamingStrategy().getName(handlerMethod, mapping);

addMappingName(name, handlerMethod);

}

this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));

}

finally {

this.readWriteLock.writeLock().unlock();

}

}

生成的数据如下:

5.系统拦截器列表初始化过程,会调用到AbstractHandlerMapping.initApplicationContext,这个会查找当前容器工厂中所有继承了MappedInterceptor类的拦截器实例BEAN.然后保存到AbstractHandlerMapping.interceptors

protected void initApplicationContext() throws BeansException {

extendInterceptors(this.interceptors);

detectMappedInterceptors(this.adaptedInterceptors);

initInterceptors();

}

二、调用HTTP请求根据PATH寻找接口方法流程

1.首先tomcat会调用DispatcherServlet.doDispatch方法,进行请求分发处理。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

HttpServletRequest processedRequest = request;

HandlerExecutionChain mappedHandler = null;

boolean multipartRequestParsed = false;

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {

ModelAndView mv = null;

Exception dispatchException = null;

try {

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());

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);

}

catch (Exception ex) {

dispatchException = ex;

}

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

}

finally {

if (asyncManager.isConcurrentHandlingStarted()) {

// Instead of postHandle and afterCompletion

if (mappedHandler != null) {

mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);

}

}

else {

// Clean up any resources used by a multipart request.

if (multipartRequestParsed) {

cleanupMultipart(processedRequest);

}

}

}

}

2.首先调用getHandler去根据请求PATH查找HandlerExecutionChain,HandlerExecutionChain就是一个RequestHandleMappinfo加上一个拦截器列表。会调用到AbstractHandlerMapping.getHandler

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

Object handler = getHandlerInternal(request);

if (handler == null) {

handler = getDefaultHandler();

}

if (handler == null) {

return null;

}

// Bean name or resolved handler?

if (handler instanceof String) {

String handlerName = (String) handler;

handler = obtainApplicationContext().getBean(handlerName);

}

HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

return executionChain;

}

3.最终会调用到AbstractHandlerMapping.lookupHandlerMethod根据PATH查找HandlerMethod,这里面的 this.mappingRegistry.getMappingsByUrl就是初始化时的URL和RequestMappingInfo映射表。

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {

List matches = new ArrayList<>();

List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);

if (directPathMatches != null) {

addMatchingMappings(directPathMatches, matches, request);

}

if (matches.isEmpty()) {

// No choice but to go through all mappings...

addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);

}

if (!matches.isEmpty()) {

Match bestMatch = matches.get(0);

request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);

handleMatch(bestMatch.mapping, lookupPath, request);

return bestMatch.handlerMethod;

}

else {

return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);

}

}

调用堆栈1

调用堆栈2

初始化HandlerExecutionChain拦截器列表,这个会查找当前容器工厂中所有实现了handleInteropr 的类,

AbstractHandlerMapping类

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {

HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?

(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);

for (HandlerInterceptor interceptor : this.adaptedInterceptors) {

if (interceptor instanceof MappedInterceptor) {

MappedInterceptor mappedInterceptor = (MappedhVDOCQVpHInterceptor) interceptor;

if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {

chain.addInterceptor(mappedInterceptor.getInterceptor());

}

}

else {

chain.addInterceptor(interceptor);

}

}

return chain;

}

这个类会根据拦截器的URL匹配规则相应添加拦截器列表。

5.调用所有拦截器的applyPreHandle方法

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {

HandlerInterceptor[] interceptors = getInterceptors();

if (!ObjectUtils.isEmpty(interceptors)) {

for (int i = 0; i < interceptors.length; i++) {

HandlerInterceptor interceptor = interceptors[i];

if (!interceptor.preHandle(request, response, this.handler)) {

triggerAfterCompletion(request, response, null);

return false;

}

this.interceptorIndex = i;

}

}

return true;

}

7.然后调用invocableMethod.invokeAndHandle(webRequest, mavContainer),首先通过反射调用handlerMethod中的bean的接口方法

ServletInvocableHandlerMethod

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,

Object... providedArgs) throws Exception {

Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

setResponseStatus(webRequest);

if (returnValue == null) {

if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {

disableContentCachingIfNecessary(webRequest);

mavContainer.setRequestHandled(true);

return;

}

}

else if (StringUtils.hasText(getResponseStatusReason())) {

mavContainer.setRequestHandled(true);

return;

}

mavContainer.setRequestHandled(false);

Assert.state(this.returnValueHandlers != null, "No return value handlers");

try {

this.returnValueHandlers.handleReturnValue(

returnValue, getReturnValueType(returnValue), mavContainer, webRhttp://equest);

}

catch (Exception ex) {

if (logger.isTraceEnabled()) {

logger.trace(formatErrorForReturnValue(returnValue), ex);

}

throw ex;

}

}

9.最后调用HandlerMethodReturnValueHandlerComposite.handleReturnValue 进行返回值处理,例如将BEAN转jsON,转XML等。

9.1 这个找HANDLER的过程也是,根据此HANDLER是否支持此方法,如在方法上加上了@ResponseBody,则会由RequestResponseBodyMethodProcessor处理。

RequestResponseBodyMethodProcessor

public boolean supportsReturnType(MethodParameter returnType) {

return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||

returnType.hasMethodAnnotation(ResponseBody.class));

}

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,

ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);

if (handler == null) {

throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());

}

handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);

}

RequestResponseBodyMethodProcessor。

此类继承了AbstractMessageConverterMethodProcessor,这个类会调用当前容器工厂中所有

9.2 由于我们在方法上加了@ResponseBody注解,所有此handler为

protected void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,

ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)

throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

Object body;

Class> valueType;

Type targetType;

if (value instanceof CharSequence) {

body = value.toString();

valueType = String.class;

targetType = String.class;

}

else {

body = value;

valueType = getReturnValueType(body, returnType);

targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());

}

if (selectedMediaType != null) {

selectedMediaType = selectedMediaType.removeQualityValue();

for (HttpMessageConverter> converter : this.messageConverters) {

GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?

(GenericHttpMessageConverter>) converter : null);

if (genericConverter != null ?

((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :

converter.canWrite(valueType, selectedMediaType)) {

body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,

(Class extends HttpMessageConverter>>) converter.getClass(),

inputMessage, outputMessage);

if (body != null) {

Object theBody = body;

LogFormatUtils.traceDebug(logger, traceOn ->

"Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");

addContentDispositionHeader(inputMessage, outputMessage);

if (genericConverter != null) {

genericConverter.write(body, targetType, selectedMediaType, outputMessage);

}

else {

((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);

}

}

else {

if (logger.isDebugEnabled()) {

logger.debug("Nothing to write: null body");

}

}

return;

}

}

}

}

9.3 messageConverts的数据初始化来源为 RequestMappingHandlerAdapter.getDefaultArgumentResolvers方法中,

resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));

messageConverts来源于RequestMappingHandlerAdapter.messageConverters中。

在初始化时会,依赖注入当前系统中所有的messageConvert.

10.最后调用拦截器的所有postHandle方法进行,处理完回调。

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)

throws Exception {

HandlerInterceptor[] interceptors = getInterceptors();

if (!ObjectUtils.isEmpty(interceptors)) {

for (int i = interceptors.length - 1; i >= 0; i--) {

HandlerInterceptor interceptor = interceptors[i];

interceptor.postHandle(request, response, this.handler, mv);

}

}

}

11.在渲染完输出视图后,会调用所有拦截器的afterCompletion方法,注意,JSON,XML这种没有视图,只有HTML等才有。

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)

throws Exception {

HandlerInterceptor[] interceptors = getInterceptors();

if (!ObjectUtils.isEmpty(interceptors)) {

for (int i = this.interceptorIndex; i >= 0; i--) {

HandlerInterceptor interceptor = interceptors[i];

try {

interceptor.afterCompletion(request, response, this.handler, ex);

}

catch (Throwable ex2) {

logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);

}

}

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:api接口网站(API接口网站源码)
下一篇:使用apache 的FileUtils处理文件的复制等操作方式
相关文章

 发表评论

暂时没有评论,来抢沙发吧~