Spring MVC框架中使用HandlerMapping来进行请求到处理器的映射处理。
那么就会有一个问题:那么框架到底是如何从Url获取到一个处理器的呢?
而回到这个问题,一般要思考两个问题:
1、框架如何初始化HandlerMapping接口.
2、 框架如何使用HandlerMapping接口进行请求到处理器的映射处理。
那么就会有一个问题:那么框架到底是如何从Url获取到一个处理器的呢?
而回到这个问题,一般要思考两个问题:
1、框架如何初始化HandlerMapping接口.
2、 框架如何使用HandlerMapping接口进行请求到处理器的映射处理。
现在,先来看看第一个问题。我们以@RequestMapping为例,是如何处理的。
其中SpringMVC容器提供了RequestMappingHandlerMapping实现类来处理这个注解.
debug源码,发现是在初始化容器的时候会注册RequestMappingHandlerMappingBean:
步骤如下:
1:在初始化容器的时候,有一个步骤:
AbstractAutowireCapableBeanFactory.initializeBeaninvoke
在这方法中有一个invokeInitMethods, 在这个代码中会执行bean.afterPropertiesSet()方法
2:afterPropertiesSet()方法
该方法是InitializingBean的一个接口,所有实现了这个接口,都要实现 afterPropertiesSet()方法。
在初始化bean的时候调用。
AbstractHandlerMethodMapping.afterPropertiesSet()
AbstractHandlerMethodMapping实现了这个接口,也就是实现了afterPropertiesSet()方法,
在初始化bean的时候会调用 AbstractHandlerMethodMapping.afterPropertiesSet()
3: initHandlerMethods()
在afterPropertiesSet()方法中调用了initHandlerMethods()方法.
这个方法用来从所有的bean中检测出符合规则的类和方法,
然后生成一个调用RequestMappingHandlerMapping.getMappingForMethod() 产生一个 RequestMappingInfo对象,
在registerHandlerMethod注册过程中:根据RequestMappingInfo对象生成一个HandlerMethod对象。
4: 注册到AbstractHandlerMethodMapping的handlerMethods和urlMap中.
这个是变量的声明
Map<T, HandlerMethod> handlerMethods;
MultiValueMap<String, T> urlMap;
会把相关的对象保存到上面的Map中.
涉及到的相关类:
InitializingBean、AbstractHandlerMethodMapping、RequestMappingHandlerMapping、R equestMappingInfo、HandlerMethod.
代码分析。。。:
一: AbstractHandlerMethodMapping.initHandlerMethods()
这个方法用来扫描容器的bean,监测出所以的映射方法(Handler Methods),并且注册到映射处理器中(HandlerMapping)。
/** * Scan beans in the ApplicationContext, detect and register handler methods. * @see #isHandler(Class) * @see #getMappingForMethod(Method, Class) * @see #handlerMethodsInitialized(Map) */ protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { if (isHandler(getApplicationContext().getType(beanName))){ detectHandlerMethods(beanName); } } handlerMethodsInitialized(getHandlerMethods()); }这个方法步骤如下:
1 :从容器中获得所有bean的名字
2:遍历容器中的bean,判断Bean是否属于Handler,如果是则检测出所以的HandlerMethod方法并且注册到容器中.
3:handlerMethodsInitialized这个方法里的方法体为空,没有做任何的处理
注意:在上面的代码中,isHandler()方法是个抽象方法,由子类来提供具体的实现。
比如 RequestMappingHandlerMapping提供了实现,代码如下:
@Override protected boolean isHandler(Class<?> beanType) { return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) || (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null)); }在这里来判断当前的bean是否有Controller或者RequestMapping注解。
再来看下detectHandlerMethods的代码
protected void detectHandlerMethods(final Object handler) { Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); // Avoid repeated calls to getMappingForMethod which would rebuild RequestMatchingInfo instances final Map<Method, T> mappings = new IdentityHashMap<Method, T>(); final Class<?> userType = ClassUtils.getUserClass(handlerType); Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { public boolean matches(Method method) { T mapping = getMappingForMethod(method, userType); if (mapping != null) { mappings.put(method, mapping); return true; } else { return false; } } }); for (Method method : methods) { registerHandlerMethod(handler, method, mappings.get(method)); } }
大概步骤如下:
1 : 通过HandlerMethodSelector.selectMethods()方法来从当前的处理器中匹配出具有映射处理的方法。
2:取出映射的方法后,则调用registerHandlerMethod()注册到处理器中。
注意:在上面代码中,getMappingForMethod(method, userType)是个抽象方法,具体由子类来实现。
比如RequestMappingHandlerMapping中提供了如下的实现:
@Override protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { RequestMappingInfo info = null; RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class); if (methodAnnotation != null) { RequestCondition<?> methodCondition = getCustomMethodCondition(method); info = createRequestMappingInfo(methodAnnotation, methodCondition); RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); if (typeAnnotation != null) { RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType); info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info); } } return info; }具体步骤:
1:从当前类中取出RequestMapping 注解。
2:如果注解不为空的话,则进行一系列处理,生成一个RequestMappingInfo对象。
再来看看registerHandlerMethod这个方法的实现,看看是是把HandlerMethod注册到哪里的?
代码:
/** * Register a handler method and its unique mapping. * @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 */ protected void registerHandlerMethod(Object handler, Method method, T mapping) { HandlerMethod newHandlerMethod = createHandlerMethod(handler, method); HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping); if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) { throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() + "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" + oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped."); } this.handlerMethods.put(mapping, newHandlerMethod); if (logger.isInfoEnabled()) { logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod); } Set<String> patterns = getMappingPathPatterns(mapping); for (String pattern : patterns) { if (!getPathMatcher().isPattern(pattern)) { this.urlMap.add(pattern, mapping); } } }
从上面代码可以看出是 注册到下面两个变量中。
private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>(); private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();
一看定义就知道, urlMap 的key是个String类型,表示的是请求url,而T应该是RequestMappingInfo.
handlerMethods 的key是RequestMappingInfo。
也就是请求的时候,会先根据请求url从urlMap中查找对应的RequestMappingInfoBean,
然后再从handlerMethods 方法中找到对应的HandlerMethod方法,这个HandlerMethod就是实际的业务处理逻辑。
总结:
这篇文章分析SpringMVC容器在初始化的时候,是如何初始化映射处理器的。
1:容器初始化的时候是在哪个入口 进入 初始化映射处理器的。
相关推荐
Spring MVC是Spring框架的一个模块,专注于构建Web应用程序。作为架构师和Java开发者,深入理解Spring MVC的原理和实践应用是非常重要的。本文通过分析Spring MVC的核心组件和执行流程,提供了一个全面的学习指南。 ...
Spring MVC运行流程,分七个步骤,1.DispatcherServlet 2.HandlerMapping
5)Spring MVC处理流程 a.首先客户端发出spring mvc请求,请求到达DispatcherServlet主控制器处理(前端控制器) b.主控制器调用HandlerMapping组件,根据请求不同调用Controller处理器 c.主控制器调用Controller方法...
Spring为展现层提供了一个优秀的Web框架——Spring MVC。和众多其它Web框架一样,它基于MVC设计理念,此外,由于它采用了松散耦合可插拔组件结构,具有比其它MVC框架更多的扩展性和灵活性。 Spring MVC框架围绕...
Spring的模型-视图-控制器(MVC)框架是围绕一个DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。...
HandlerMapping接口 HandlerAdapter接口 Controller接口 HandlerInterceptor 接口 View接口 LocalResolver接口HandlerExceptionResolver接口 ModelAndView类 。
13.5.1 初始化Model192 13.5.2 更新Model197 13.6 ServletInvocableHandlerMethod199 13.6.1 HandlerMethod199 13.6.2 InvocableHandlerMethod203 13.6.3 ServletInvocableHandler-Method205 13.7 ...
分类专栏: java框架 文章标签: ...spring实现业务对象管理,mybatis作为数据对象的持久化引擎 springMVC执行流程: 1. 客户端将请求统一提交到DispatcherServlet; 2. DispatcherServlet会将请求交给HandlerMapping
Spring MVC之DispatcherServlet 使用Spring MVC,配置DispatcherServlet是第一步。 ...“某某规则”:是根据你使用了哪个HandlerMapping接口的实现类的不同而不同。 先来看第一个例子: <w
Spring MVC以DispatcherServlet为核心,众多组件如HandlerMapping为辅助,为用户封装了请求映射等底层逻辑,让用户可以更专注与业务逻辑的处理。本文会对Spring MVC整体结构做简单介绍。 Spring MVC结构图 Spring ...
2、 DispatcherServlet把请求转交给HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器对象、多个HandlerInterceptor拦截器)对象.(后面会学习到拦截器) 3、 ...
DispatcherServlet是前端控制器设计模式的实现,提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。 具体请参考第二章的图2-1。 ...
1. 客户端请求提交到DispatcherServlet 2. 由DispatcherServlet控制器查询个或多个HandlerMapping,找到处理 3
Spring MVC 内置了 Requestmapping、HandlerMapping 和 ViewResolver 等组件,可以简化开发流程。MyBatis 作为持久层框架,负责处理数据库操作。 在安全性方面,该网站采用了 SSL 证书进行加密传输,并实现了用户...
只有对应的HandlerMapping (为了实现类型级别的注解)和/ 或HandlerAdapter (为了实现方法级别的注解)出现在 dispatcher中时, @RequestMapping 才会被处理。 这在DispatcherServlet 和DispatcherPortlet 中都是...
Spring MVC的拦截器,是属于HandlerMapping级别的,可以有多个HandlerMapping ,每个HandlerMapping可以有自己的拦截器,具体内容详情大家通过本文学习吧
Spring MVC 内置了 Requestmapping、HandlerMapping 和 ViewResolver 等组件,可以简化开发流程。MyBatis 作为持久层框架,负责处理数据库操作。 在安全性方面,该教务管理系统采用了 SSL 证书进行加密传输,并实现...
1.spring mvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作。 2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller. 3....
java进阶源码分析专题常用设计模式线程与并发锁的使用深度理解synchronized、...mvc基于注解的事件驱动基于SpringJDBC手写ORM框架SpringMVC九大组件手写实现SpringMVC框架SpringMVC和Struts2对比分析Spring5新特性...
Spring MVCSpringMVC框架介绍Spring框架提供了构造Web应用程序的全能MVC模块。Spring MVC分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行制定。是一个标准的MVC框架。SpringMVC...