首先先明白 SpringMvcContract类是做什么的:
该类继承了Contract.BaseContract并实现了ResourceLoaderAware接口,
其作用就是对RequestMapping、RequestParam、RequestHeader等注解进行解析的。
在了解了SpringMvcContract类的作用后,要想知道该类调用时机,最简单的办法就是找一个调用feign接口的方法,打断点去观察requestTemplate的生成过程,看在什么时候把注解解析成请求模板的。在项目启动之前,我就把SpringMvcContract类中的方法打了断点,但是让我奇怪的是,在项目启动的过程中,就直接进到该类的断点了,难道是在项目启动时,调用的吗?带着这个问题,我放掉了断点,并让项目启动完成,开始调用app-service中的 会员查询详情及卡查询 接口,这个接口调用了ZexMemberFeignClient 的 全渠道会员查询接口,通过断点的调试,我发线了requestTemplate的形成流程图如下:
在encode之后,requestTemplate就已经将请求头文件、入参等数据封装好了,并且问题是,在此过程中并未调用SpringMvcContract类去解析注解,反而是在invoke之后,注解就已经被解析了。
然后我百度了feign的实现原理,明白了feign是通过JDK动态代理来生成RequestTemplate的,也就对前面的疑问有了答案:在项目启动时,会程序包扫描,对包下所有@FeignClient注解的类,并注入到Spring的IOC容器中,而SpringMvcContract类就是在此时提供解析规则,生成MethodHanderMap。在程序调用feign接口时,会通过invoke获取对应容器下的解析规则,encode之后生成完整的request请求。