前情回顾
上篇我们已经完成了网关对所有微服务请求的拦截以及JWT的登录校验。
客户端和微服务之间的桥梁--网关(身份校验)https://mp.csdn.net/mp_blog/creation/editor/143425484
问题引入
现在的问题是在一些微服务业务中,需要用到用户信息,但是并没有,不能仅仅只是简单的校验,还要把信息传递过去。如何通过网关传递给微服务。
思路
网关过滤器中把用户信息写在请求头中发送过去,微服务可以通过注解@RequestHeader再从请求头中获取信息。
衍生问题的思路:对于一个服务中N个业务都需要用到户信息,可以用拦截器把用户信息保存到 ThreadLocal ,避免增加重复的逻辑。
对于N个服务,可以把拦截器写在服务外的公共模块,作为依赖引入使用,避免 重复的定义拦截器。
思路实现
构建新的exchange对象
使用mutate(使改变)方法创建一个新的构造器对exchange对象进行复制并重构,然后修改一些请求头信息,生成一个新的exchange对象,放行的时候,将这个新的对象上下文传递就可以了。
构造器对request请求进行构建,builder请求构建器,向请求头添加了一个新的头信息“user”
定义外部公共模块,编写MVC拦截器
微服务只要引入这个公共模块依赖,拦截器即可生效。此拦截器不进行拦截,仅仅只做将用户信息保存到ThreadLocal的操作
注:此时拦截器以及配置类是定义在公共模板中的,和微服务不在一个包,是扫描不到配置的
使用springboot的自动装配
使在不同包下的配置类生效:将配置类记录在META-INF/spring.factories中,当应用启动时,会尝试加载此文件。
此时启动网关会报错
Failed to process import candidates for configuration class [com.hmall.gateway.GatewayApplication]; nested exception is java.io.FileNotFoundException: class
因为网关也引用了公共模块,也就有了拦截器的MVC配置类。而网关和SpringMVC的架构,目标是不一样的,网关非阻塞式I/O,MVC阻塞式I/O,一起用就产生了冲突。
解决:只让此配置类在微服务中生效,使用条件自动装配,微服务都用到了MVC,而MVC的核心API是DispatcherServlet,所以条件就是它。
@ConditionalOnClass
: 当某个类在类路径中存在时才装配对应的 bean,即在加载META-INF/spring.factories 前进行条件检查,决定要不要加载某个配置。
所以:只有当类路径中存在DispatcherServlet时,才会加载此配置类,以确保当前应用是一个MVC应用
再启动网关,成功启动。
至此,微服务就可以从ThreadLocal中获取到用户信息了。
预知后事如何,请看下集。