SpringMVC源码阅读HandlerMapping初始化-RequestMappingHandlerMapping(六)
我们常用的使用方式就是@Contorller 和@RequsetMappig方式 就是通过RequestMappingHandlerMapping实现
类图
AbstractHandlerMapping上一篇已经说过了 我们主要看红线框起来的
AbstractHandlerMethodMapping
实现了InitializingBean接口 spring托管初始化 就会调用这个方法
afterPropertiesSet
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet
public void afterPropertiesSet() { this.initHandlerMethods(); } protected void initHandlerMethods() { if (this.logger.isDebugEnabled()) { this.logger.debug("Looking for request mappings in application context: " + this.getApplicationContext()); } //获得容器中所有的bean的名字 String[] beanNames = this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.obtainApplicationContext(), Object.class) : this.obtainApplicationContext().getBeanNamesForType(Object.class); String[] var2 = beanNames; int var3 = beanNames.length; for(int var4 = 0; var4 < var3; ++var4) { String beanName = var2[var4]; //不是scopedTarget开头的 if (!beanName.startsWith("scopedTarget.")) { Class beanType = null; try { //获得bean对象对应类的class beanType = this.obtainApplicationContext().getType(beanName); } catch (Throwable var8) { if (this.logger.isDebugEnabled()) { this.logger.debug("Could not resolve target class for bean with name '" + beanName + "'", var8); } } //<1>判断是否是Handler类 比如判断是否打上了@Contorller 由子类实现注解 if (beanType != null && this.isHandler(beanType)) { //<2>解析BeeanMethods this.detectHandlerMethods(beanName); } } } //空实现 传入解析号的HandleMethods this.handlerMethodsInitialized(this.getHandlerMethods()); }
<1>isHandler
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#isHandler
protected boolean isHandler(Class<?> beanType) { //是否打上了Controller 注解 或者是否打上了RequestMapping 如果父类打上了也会被扫描到 比如Controller打的@Service注解 父类打的@Controller return AnnotationUtils.findAnnotation(beanType, Controller.class) != null || AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null; }
<2>detectHandlerMethods
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#detectHandlerMethods
protected void detectHandlerMethods(Object handler) { //如果是传入的beanname则从容器里面获得指定bean的Type如果是对象 则直接获取classs Class<?> handlerType = handler instanceof String ? this.obtainApplicationContext().getType((String)handler) : handler.getClass(); if (handlerType != null) { //暂时不造干嘛 正常情况是=handlerType Class<?> userType = ClassUtils.getUserClass(handlerType); /** * 这里会遍历获取class的公共的方法 如果 是重写的父类方法 则获取父类的method * 筛选查打上了@RequstMapping的方法 */ Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (method) -> { try { /** * <3>这里this 是AbstractHandlerMethodMapping getMappingForMethod是抽象方法由子类实现主要用于判断是否是打上了@RequestMapping的方法 * 并封装成RequestMappingInfo 封装了完整路由信息 如:/user/login * 如果不死 则返回null */ return this.getMappingForMethod(method, userType); } catch (Throwable var4) { throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, var4); } }); if (this.logger.isTraceEnabled()) { this.logger.trace("Mapped " + methods.size() + " handler method(s) for " + userType + ": " + methods); } methods.forEach((method, mapping) -> {
<4> Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); /** * <5>注册到mappingRegistry invocableMethod为方法 mapping为完整路由信息 */ this.registerHandlerMethod(handler, invocableMethod, mapping); }); } }
到这里mappingRegistry 就封装了所有handler和路由信息
RequestMappingHandlerMapping
<3>getMappingForMethod
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#detectHandlerMethods
->
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#getMappingForMethod
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { //<6>获取方法上的@RequstMapping注解并封装成RequestMappingInfo RequestMappingInfo info = this.createRequestMappingInfo(method); if (info != null) { //<6>这里就是对应获取Contorller上面的@RequstMapping注解 RequestMappingInfo typeInfo = this.createRequestMappingInfo(handlerType); if (typeInfo != null) { //这里主要是2个info合并成一个 就是url拼接 controler的RequstMapping注解和方法的@RequestMapping注解拼接 info = typeInfo.combine(info); } /** * private Map<String, Predicate<Class<?>>> pathPrefixes = new LinkedHashMap(); * 这里是利用成员变量 判断是否给此handlerType 加上指定前缀 没发现杂用 */ String prefix = this.getPathPrefix(handlerType); //如果有配置加上前缀 if (prefix != null) { info = RequestMappingInfo.paths(new String[]{prefix}).build().combine(info); } } return info; }
<6>createRequestMappingInfo
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#detectHandlerMethods
->
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#getMappingForMethod
->
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#createRequestMappingInfo(java.lang.reflect.AnnotatedElement)
@Nullable private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) { //获得requestMapping注解对象 RequestMapping requestMapping = (RequestMapping) AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class); RequestCondition<?> condition = element instanceof Class ? this.getCustomTypeCondition((Class)element) : this.getCustomMethodCondition((Method)element); //封装成RequestMappingInfo return requestMapping != null ? this.createRequestMappingInfo(requestMapping, condition) : null; }
<5>registerHandlerMethod
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#detectHandlerMethods
->
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod
protected void registerHandlerMethod(Object handler, Method method, T mapping) { this.mappingRegistry.register(mapping, handler, method); } public void register(T mapping, Object handler, Method method) { //ReentrantReadWriteLock 写锁 this.readWriteLock.writeLock().lock(); try { //将handler 和method封装为HandlerMethod 内部维护了控制器 控制器方法 参数等信息 HandlerMethod handlerMethod = AbstractHandlerMethodMapping.this.createHandlerMethod(handler, method); this.assertUniqueMethodMapping(handlerMethod, mapping); this.mappingLookup.put(mapping, handlerMethod); List<String> directUrls = this.getDirectUrls(mapping); Iterator var6 = directUrls.iterator(); while(var6.hasNext()) { String url = (String)var6.next(); //url为路由url mapping为RequestMapppingInfo this.urlLookup.add(url, mapping); } String name = null; if (AbstractHandlerMethodMapping.this.getNamingStrategy() != null) { name = AbstractHandlerMethodMapping.this.getNamingStrategy().getName(handlerMethod, mapping); this.addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = AbstractHandlerMethodMapping.this.initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } /** * key为Mapping info 存储路由信息 * value为MappingRegistration 内部封装了HandlerMethod和mappingInfo */ this.registry.put(mapping, new AbstractHandlerMethodMapping.MappingRegistration(mapping, handlerMethod, directUrls, name)); } finally { this.readWriteLock.writeLock().unlock(); } }
总结
1.我们常用的注解配置是通过实现spring 的InitializingBean接口进行初始化
2.会活动容器里面所有的bean 3.判断是Handle(是否打上了@Contorller注解)
3.遍历这些Handle所有的方法遍历是否是方法Handle(是否打上了@RequestMapping)
4封装成HandleMappingInfo返回 保存了路由信息
5.最终会解析成HandleMethod保存起来 保存了控制器信息 方法信息 对象工厂信息 通过HandleMappingInfo为key HandleMethod为Value保存起来
6.后续就可以快速找到对一个的Handle处理