springmvc的handler收集

在上一篇中我们大概分析了springmvc的流程处理,但是我们会发现一个最重要的问题:我们知道的springmvc初始化ioc的时机以及他的运行流程。在流程分析的时候,我们可以看到他是直接从一个urlLookup(Map)中去取handler的。但是对于hander的收集这一块又是什么时候去进行的?他又是什么时候将handler与其对应的uri封装到urlLookup中得?以及MappingHandler是什么时候创建?他里面都封装了哪些handler?

1、onRefresh的作用

在前面对于ioc容器的分析我们得知:在bean实例化之后,ioc会对监听器里面的方法进行调用。
同样,在springmvc的ioc容器实例化之后,他也会调用监听器的方法

监听器:
SourceFilteringListener 调用下面的监听器的 onApplicationEvent
GenericApplicationListenerAdapter调用下面监听器的onApplicationEvent
ContextRefreshListener

最终代码会停在这一块

FrameworkServlet  631  line

//容器创建之后的回调事件~~~  往下看
FrameworkServlet.this.onApplicationEvent(event);

事件回调

FrameworkServlet  413 line

public void onApplicationEvent(ContextRefreshedEvent event) {
        this.refreshEventReceived = true;
        synchronized(this.onRefreshMonitor) {
            //往下看
            this.onRefresh(event.getApplicationContext());
        }
    }

DispatcherServlet  134 line

protected void onRefresh(ApplicationContext context) {
		//继续往下看
        this.initStrategies(context);
    }

DispatcherServlet  138 line

protected void initStrategies(ApplicationContext context) {
		//初始化文件解析器
        this.initMultipartResolver(context);
        //初始化locale语言解析器
        this.initLocaleResolver(context);
        //初始化主题解析器
        this.initThemeResolver(context);
        //初始化handerMapping???就是这个咯
        this.initHandlerMappings(context);
        //初始化handlerAdapter  ??这个就是最终执行hanler的代理器咯
        this.initHandlerAdapters(context);
        //异常解析器
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        //初始化视图解析器
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
    }

2、handlerMappings的初始化

2.1 初始化handlerMappings

DispatcherServlet  201  line

private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
        if (this.detectAllHandlerMappings) {
        	//加载handlerMappings    直接从ioc容器中获取类型为HandlerMapping的类
            Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerMappings = new ArrayList(matchingBeans.values());
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        } 
        如果上一步没获取到   则在这里获取默认的handlerMapping
        ......
    }

上面代码很简单。直接从ioc中取。那么我们可以肯定,在加载handlerMapping的时候,他就会将uri与对应的handler注册近handlerMapping中。

那么,我们就简单分析一下handlerMapping的加载吧

2.2 ioc加载handlerMapping

从上一篇我们知道hander与对应的uri是在urlLookup中封装的,那么他肯定调用urlLookup的put方法去放。所以,我们直接在他put的时候打一个断点,然后去分析整个调用栈就知道大概情况了

在这里插入图片描述

从调用栈可以知道,他是在属性设置完之后,遍历所有的bean,然后获取标注了@RequestMapping注解的方法,然后去将注解中的值与方法提取出来,最后在设置给urlLookup的。那么我们就可以在接收到web请求之后,直接来这里取对应的handler了

由于他是取得ioc容器中的bean。
那么,如何保证在加载HandlerMapping的时候,我们的业务处理的bean已经被加载好了呢?

通过查看AbstractHandlerMethodMapping.processCandidateBean(String beanName)发现,它会根据beanName获取beanType,然后只有type类型为Handler的bean,才会进行注册近handlerMapping。并且注册的时候,也不需要获取类的实例,而是根据反射获取到类的方法,然后去将@RequestMapping注解的方法,然后去将注解中的值与方法提取出来进行设置。

由于代码量太庞大,并且逻辑过于复杂
具体的代码这一块就不分析了,大家可以根据我截图的红圈标注信息,去打断点看详细信息

关键代码
删选类型为handler的beanName
AbstractHandlerMethodMapping.processCandidateBean(String beanName)
提取方法与接口并注册
AbstractHandlerMethodMapping.detectHandlerMethods(Object handler)

3、handlerAdapter的初始化

前面我们知道需要根据一个handler去获取一个handlerAdapter,然后调用adapter的hand()方法去执行我们的业务逻辑,其实最终的业务执行还是使用我们的controller,只不过这一块会使用adaptor对其他的一些必要信息进行一个模板化的处理,只有真正业务才会使用我们的controller来执行。 后续在modelAndView的生成那块再来具体分析

handlelAdapter的初始化

DispatcherServlet  226  line

private void initHandlerAdapters(ApplicationContext context) {
        this.handlerAdapters = null;
        if (this.detectAllHandlerAdapters) {
        	//从ioc容器中获取所有HandlerAdapter类型的bean,并与其name一起封装到map中
            Map<String, HandlerAdapter> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
            if (!matchingBeans.isEmpty()) {
                this.handlerAdapters = new ArrayList(matchingBeans.values());
                AnnotationAwareOrderComparator.sort(this.handlerAdapters);
            }
        } else {
            try {
            	//这一块获取名字为handlerAdapter的bean  由此可见,我们可自己去定制这个bean
                HandlerAdapter ha = (HandlerAdapter)context.getBean("handlerAdapter", HandlerAdapter.class);
                this.handlerAdapters = Collections.singletonList(ha);
            } catch (NoSuchBeanDefinitionException var3) {
            }
        }

		//获取一个默认的handlerAdapter
        if (this.handlerAdapters == null) {
            this.handlerAdapters = this.getDefaultStrategies(context, HandlerAdapter.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No HandlerAdapters declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
            }
        }

    }

由此可见handlerAdapter与handlerMapping的获取方式都一样,直接从ioc容器中获取。那么也可以知道,他也是在设置完bean的属性之后,将adapter与handler进行的一个关系绑定。所以后面可以根据handler去拿到adapter。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring MVC中的Handler方法是用来处理HTTP请求的方法。在Spring MVC中,通过注解将一个普通的Java方法标记为一个Handler方法,并将其映射到特定的URL路径和HTTP请求方法。 常用的Handler方法注解有: 1. @RequestMapping:用于将Handler方法映射到指定的URL路径和HTTP请求方法。可以设置URL路径、请求方法、请求头等条件。 2. @GetMapping、@PostMapping、@PutMapping、@DeleteMapping:分别用于将Handler方法映射到GET、POST、PUT、DELETE请求。 3. @PathVariable:用于获取URL路径中的变量值,并将其作为方法参数。 4. @RequestParam:用于获取请求参数的值,并将其作为方法参数。 5. @RequestBody:用于获取请求体中的数据,并将其转换为方法参数的类型。 6. @ResponseBody:用于将方法返回值直接作为响应体返回给客户端。 一个典型的Handler方法示例如下: ```java @Controller @RequestMapping("/users") public class UserController { @GetMapping("/{id}") @ResponseBody public User getUserById(@PathVariable("id") Long id) { // 根据id查询用户信息并返回 } @PostMapping @ResponseBody public User createUser(@RequestBody User user) { // 创建用户并返回 } @PutMapping("/{id}") @ResponseBody public User updateUser(@PathVariable("id") Long id, @RequestBody User user) { // 根据id更新用户信息并返回 } @DeleteMapping("/{id}") @ResponseBody public void deleteUser(@PathVariable("id") Long id) { // 根据id删除用户 } } ``` 以上示例中,`@RequestMapping`注解将`UserController`类映射到"/users"路径下。`@GetMapping`、`@PostMapping`、`@PutMapping`、`@DeleteMapping`注解分别将不同的Handler方法映射到不同的HTTP请求方法。`@PathVariable`注解用于获取URL路径中的变量值,`@RequestBody`注解用于获取请求体中的数据。`@ResponseBody`注解将方法返回值直接作为响应体返回给客户端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值