目錄
- 推薦公衆号
- 引言
- 上一篇
- 正文
-
- initHandlerMethods
- registerHandlerMethod
- 維護關系的map集合說明
推薦公衆号
有彩蛋哦!!!(或者公衆号内點選網賺擷取彩蛋)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyAjN0AjN0IjM5ITMxgTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
引言
現在大緻有個概念,HandlerMapping維護url和HandlerMethod之間的關系
HandlerMethod包含的資訊是:類,方法,參數
HandlerAdapter是具體執行HandlerMethod的
DispatcherServlet在接到請求後就根據HandlerMapping找到HandlerMethod
HandlerAdapter執行HandlerMethod
這篇解釋SpringMVC是如何維護url和HandlerMethod()之間的關系
上一篇
SpringMVC(八)-----AbstractHandlerMapping
https://blog.csdn.net/yueloveme/article/details/89878530
正文
initHandlerMethods
/**
* Detects handler methods at initialization.
*/
AbstractHandlerMethodMapping
項目啟動時會調用這個方法維護url和HandlerMethod之間的關系
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #isHandler(Class)
* @see #getMappingForMethod(Method, Class)
* @see #handlerMethodsInitialized(Map)
*/
AbstractHandlerMethodMapping
這個方法會循環周遊Spring IOC容器中的bean 将有 Controller RequestMapping等注解的bean
維護url和HandlerMethod關系
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " +
getApplicationContext());
}
IOC中所有bean
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);
}
}
isHandler(beanType) 判斷是否有Controller等注解
if (beanType != null && isHandler(beanType)) {
維護關系
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
/**
* {@inheritDoc}
* <p>Expects a handler to have either a type-level @{@link Controller}
* annotation or a type-level @{@link RequestMapping} annotation.
*/
RequestMappingHandlerMapping
判斷是否有 Controller RequestMapping注解
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
/**
* Look for handler methods in a handler.
* @param handler the bean name of a handler or a handler instance
*/
AbstractHandlerMethodMapping
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) :
handler.getClass());
final Class<?> userType = ClassUtils.getUserClass(handlerType);
目前bean中所有的可以請求的方法(也就是@RequestMapping定義的接口)
方法轉成RequestMappingInfo(包含url,請求類型GET,POST等資訊)
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler
class [" +
userType.getName() + "]: " + method, ex);
}
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " +
userType + ": " + methods);
}
注冊 關系 裡面維護了幾個map集合
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(),
userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
registerHandlerMethod
/**
* Register a handler method and its unique mapping. Invoked at startup for
* each detected handler method.
* @param handler the bean name of the handler or the handler instance
* @param method the method to register
* @param mapping the mapping conditions associated with the handler method
* @throws IllegalStateException if another method was already registered
* under the same 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 handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
維護 RequestMappingInfo 和 HandlerMethod之間的關系
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
維護了 url(例如 /api/users) 和 RequestMappingInfo
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
維護了 方法名 和 對應HandlerMethod集合的關系
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method,
mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
維護 RequestMappingInfo和 MappingRegistration之間的關系
MappingRegistration包含 下面資訊
this.registry.put(mapping, new MappingRegistration<T>(mapping,
handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
維護關系的map集合說明
class MappingRegistry {
維護 T 和 MappingRegistration之間的關系 MappingRegistration包含
資訊看上面代碼
private final Map<T, MappingRegistration<T>> registry = new HashMap<T,
MappingRegistration<T>>();
維護 T 和 HandlerMethod之間的關系 T一般是RequestMappingInfo
HandlerMethod 包含了 類 方法 參數資訊
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T,
HandlerMethod>();
維護了 url(例如 /api/users) 和 T 之間的關系 T一般是RequestMappingInfo(包含url和
請求方式等資訊)
一個url 可能對應多個RequestMappingInfo
比如 /api/users 對應 /api/users POST 和 /api/users GET
private final MultiValueMap<String, T> urlLookup = new
LinkedMultiValueMap<String, T>();
維護了 方法名(方法名規則控制器名稱的大寫字母+#+方法名) 和 對應HandlerMethod集合的關
系 因為同樣的方法名可能對應多個不同的HandlerMethod
方法名規則 例如 控制器叫StudentController 其中一個方法名叫 addStudent 那麼
addStudent 的方法名叫 SC#addStudent
private final Map<String, List<HandlerMethod>> nameLookup =
new ConcurrentHashMap<String, List<HandlerMethod>>();
private final Map<HandlerMethod, CorsConfiguration> corsLookup =
new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();