SpringMVC源码 HandlerMapping和HandlerAdapter(3)
来源:互联网 发布:网络迷宫 mkv 编辑:程序博客网 时间:2024/05/02 02:17
上一节主要阅读了BeanNameUrlHandlerMapping类,并理清了它的父类关系,值得注意的是它的爷爷的爸爸也就是AbstractHandlerMapping实现了HandlerMapping接口,而继承了WebApplicationObjectSupport类,在AbstractDetectingUrlHandlerMapping类中,有这样一个方法:
- /**
- * Calls the {@link #detectHandlers()} method in addition to the
- * superclass's initialization.
- */
- @Override
- public void initApplicationContext() throws ApplicationContextException {
- super.initApplicationContext();
- detectHandlers();
- }
上一节没有说明这个,经过我翻WebApplicationObjectSupport类和它的父类ApplicationObjectSupport发现有一个setApplicationContext(ApplicationContext context)方法,在其中调用了initApplicationContext方法,前面的setter肯定是在bean构造时用到的,更上层的以后再去阅读理解吧,到这里就追溯到了handler探测的本源。
DefaultAnnoationHandlerMapping类也是继承自AbstractDetectingUrlHandlerMapping类,则必然实现了它的抽象方法:
- /**
- * Determine the URLs for the given handler bean.
- * @param beanName the name of the candidate bean
- * @return the URLs determined for the bean,
- * or <code>null</code> or an empty array if none
- */
- protected abstract String[] determineUrlsForHandler(String beanName);
那么detectHandler接下来的执行顺序就和上一节的顺序相同,这时我们跳到了DefaultAnnoationHandlerMapping类中的该方法:
- /**
- * Checks for presence of the {@link org.springframework.web.bind.annotation.RequestMapping}
- * annotation on the handler class and on any of its methods.
- */
- @Override
- protected String[] determineUrlsForHandler(String beanName) {
- ApplicationContext context = getApplicationContext();
- Class<?> handlerType = context.getType(beanName);
- RequestMapping mapping = context.findAnnotationOnBean(beanName, RequestMapping.class);
- if (mapping != null) {
- // @RequestMapping found at type level
- this.cachedMappings.put(handlerType, mapping);
- Set<String> urls = new LinkedHashSet<String>();
- String[] typeLevelPatterns = mapping.value();
- if (typeLevelPatterns.length > 0) {
- // @RequestMapping specifies paths at type level
- String[] methodLevelPatterns = determineUrlsForHandlerMethods(handlerType);
- for (String typeLevelPattern : typeLevelPatterns) {
- if (!typeLevelPattern.startsWith("/")) {
- typeLevelPattern = "/" + typeLevelPattern;
- }
- for (String methodLevelPattern : methodLevelPatterns) {
- String combinedPattern = getPathMatcher().combine(typeLevelPattern, methodLevelPattern);
- addUrlsForPath(urls, combinedPattern);
- }
- addUrlsForPath(urls, typeLevelPattern);
- }
- return StringUtils.toStringArray(urls);
- }
- else {
- // actual paths specified by @RequestMapping at method level
- return determineUrlsForHandlerMethods(handlerType);
- }
- }
- else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) {
- // @RequestMapping to be introspected at method level
- return determineUrlsForHandlerMethods(handlerType);
- }
- else {
- return null;
- }
- }
既然是默认注解支持的HandlerMapping,那么它必然是去探测@RequestMapping所注解的Handler和Method。这里就有必要来看看RequestMapping接口的定义:
- @Target({ElementType.METHOD, ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Mapping
- public @interface RequestMapping {
- String[] value() default {};
- RequestMethod[] method() default {};
- String[] params() default {};
- String[] headers() default {};
- }
value数组显然是存储所有该Handler中的url,method则是POST GET等方法,RequestMethod是一个enum类型
- public enum RequestMethod {
- GET, HEAD, POST, PUT, DELETE, OPTIONS, TRACE
- }
context.findAnnotationOnBean(beanName, RequestMapping.class)显然是查找了该Handler上所有使用了@RequestMapping的注解,将它们的value,method取出,再封装到RequestMapping类对象中。接下来的加入缓存语句就不用解释了。
我们来看看determineUrlsForHandlerMethods方法的源码:
- /**
- * Derive URL mappings from the handler's method-level mappings.
- * @param handlerType the handler type to introspect
- * @return the array of mapped URLs
- */
- protected String[] determineUrlsForHandlerMethods(Class<?> handlerType) {
- final Set<String> urls = new LinkedHashSet<String>();
- Class<?>[] handlerTypes =
- Proxy.isProxyClass(handlerType) ? handlerType.getInterfaces() : new Class<?>[]{handlerType};
- for (Class<?> currentHandlerType : handlerTypes) {
- ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
- public void doWith(Method method) {
- RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
- if (mapping != null) {
- String[] mappedPaths = mapping.value();
- for (String mappedPath : mappedPaths) {
- addUrlsForPath(urls, mappedPath);
- }
- }
- }
- });
- }
- return StringUtils.toStringArray(urls);
- }
这里就比较麻烦了,先从字面意思理解就是查询类中的方法,找到方法对应的RequestMapping的所包含的value,组成一个url数组。
接下来看它的实现,首先是检查了handlerType是否是一个代理类
- /**
- * Returns true if and only if the specified class was dynamically
- * generated to be a proxy class.
- */
- public static boolean isProxyClass(Class<?> cl) {
- if (cl == null) {
- throw new NullPointerException();
- }
- return proxyClasses.containsKey(cl);
- }
- /** set of all generated proxy classes, for isProxyClass implementation */
- private static Map proxyClasses =
- Collections.synchronizedMap(new WeakHashMap());
接下来是反射和回调,我也看到云里雾里的。。。。理解不来,以后再想吧,直到它最后是得到的url就行了。
handlerType.getInterfaces();
用于得到所有handlerType实现的接口的Class对象
new Class<?>[]{handlerType}
得到的还只是handlerType的Class对象
- SpringMVC源码 HandlerMapping和HandlerAdapter(3)
- SpringMVC源码 HandlerMapping和HandlerAdapter(1)
- SpringMVC源码 HandlerMapping和HandlerAdapter(2)
- SpringMVC源码 HandlerMapping和HandlerAdapter(4)
- 【推荐】SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门
- SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门
- SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门
- SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门
- SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门
- SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门
- SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门
- SpringMVC源码总结(一)HandlerMapping和HandlerAdapter入门
- SpringMVC源码分析 之 HandlerMapping和HandlerAdapter
- SpringMVC handlerMapping和handlerAdapter
- SpringMVC之HandlerMapping和HandlerAdapter
- SpringMVC之 HandlerAdapter和handlerMapping
- Spring MVC源码浅析(HandlerMapping和HandlerAdapter)
- SpringMVC学习(三)--handlerMapping和handlerAdapter
- MySQL数据类型char与varchar中数字代表的究竟是字节数还是字符数?
- java连接Access数据库
- sqlserver控制流语句
- RHEL6.5 更改Shell版本
- Redis的Java客户端Jedis的八种调用方式(事务、管道、分布式)介绍
- SpringMVC源码 HandlerMapping和HandlerAdapter(3)
- iOS应用内跳转系统设置相关界面的方法
- StringUtils类
- 贪心算法 最优装载问题
- thread_Timer(线程中定时器)
- C#网络编程参考博客
- 欢迎使用CSDN-markdown编辑器
- HDFS数据迁移解决方案之DistCp工具的巧妙使用
- 选区的基本操作