When we annotate the class @ Controller and annotate the method @ RequestMapping in actual development, how does he know the corresponding method when requesting. Before the introduction, first understand how to load the mapped Lu Jin when spring starts.
In Spring MVC, there is an interface HandlerMapping that deals with request mapping,
HandlerMapping is an interface. It has many subclasses. The following describes a very important class.
RequestMappingHandlerMapping let's first take a look at the abstract parent class AbstractHandlerMethodMapping of RequestMappingHandlerMapping, omit other methods, and focus on these two related core methods first:
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { @Override public void afterPropertiesSet() { initHandlerMethods(); int total = this.getHandlerMethods().size(); if ((logger.isTraceEnabled() && total == 0) || (logger.isDebugEnabled() && total > 0) ) { logger.debug(total + " mappings in " + formatMappingName()); } } protected void initHandlerMethods() { String[] beanNames = obtainApplicationContext().getBeanNamesForType(Object.class); for (String beanName : beanNames) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { Class<?> beanType = null; try { beanType = obtainApplicationContext().getType(beanName); }catch (Throwable ex) { if (logger.isTraceEnabled()) { logger.trace("Could not resolve type for bean '" + beanName + "'", ex); } } if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); } } } handlerMethodsInitialized(getHandlerMethods()); } }
You can see that AbstractHandlerMethodMapping implements the InitializingBean interface. When Spring initializes a bean, if the bean implements the InitializingBean interface, it will automatically call the afterPropertiesSet method
The initHandlerMethods method, as its name suggests, initializes HandlerMethods. Check whether it is called by the afterpropertieset method. This method represents that when the bean is initialized in the container, it will execute the initHandlerMethods method.
What exactly does the initHandlerMethods method do? Take a look at the business inside the method. First, get all the bean names in the container and put them into the array beanNames; Then, traverse the array, get the bean type of each bean, make a judgment on each bean type, ishandler (bean type), check the implementation of this method, and enter RequestMappingHandlerMapping:
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping implements EmbeddedValueResolverAware { @Override protected boolean isHandler(Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); } }
The above code is mainly used to judge whether the class is annotated with @ Controller or @ RequestMapping. Click inside to view the implementation of the AnnotatedElementUtils.hasAnnotation method:
public static boolean hasAnnotation(AnnotatedElement element, Class<? extends Annotation> annotationType) { if (element.isAnnotationPresent(annotationType)) { return true; } return Boolean.TRUE.equals(searchWithFindSemantics(element, annotationType, null, alwaysTrueAnnotationProcessor)); }
After judgment, the detectHandlerMethods method continues to be executed
protected void detectHandlerMethods(final Object handler) { Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { final Class<?> userType = ClassUtils.getUserClass(handlerType); Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> getMappingForMethod(method, userType)); if (logger.isTraceEnabled()) { logger.trace(formatMappings(userType, methods)); } methods.forEach((key, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(key, userType); registerHandlerMethod(handler, invocableMethod, mapping); }); } } protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); }
This method filters out the annotated @ RequestMapping methods in the class and puts them into the Map collection methods. Then, go through each method, enter the registerHandlerMethod method method, and register them in the mapping registry mappingRegistry. These maps are very important. They are judged from the inside when requesting.
So far, we understand that when Spring initializes the bean, we put all the classes with @ Controller and @ RequestMapping, find the method with @ RequestMapping in the class and put it into the map,
When the http request comes, go directly to the map to quickly get the corresponding information.
This article is transferred from: https://blog.csdn.net/songzehao/article/details/84979847