各位 30cm, 问一下 所谓的 service 层中怎么优雅获取当前用户

dengji85 1月前 28

以前一直习惯用 ThreadLocal,但在异步下就不知道怎么搞了,InheritableThreadLocal 的话,没有找到清除用户的入口,filter 肯定不行了,请求结束子线程还没完成不可能去把数据清理掉,求各位大佬指点。 现在的问题是很多代码当初只考虑的是单线程,直接 service 层获取登陆用户,现在要异步的话代码全报错了,当初这种写法是不是不能用

最新回复 (29)
  • buzaiyouyu123 24天前
    引用 2
    1.异步线程可以设置上下文,通过上下文传递
    2.想办法在子线程前后织入登录用户相关的信息,即 Context
    3.阿里的 TTL ( transmittable-thread-local )可以参考
  • buzaiyouyu123 24天前
    引用 3
    或者自己来实现一个线程池的 wrapper
  • HariopaNic 24天前
    引用 4
    自愧不如没有 30,只有 18
  • lance7in 24天前
    引用 5
    不敢当不敢当
    18cm 来观赏各位巨巨的优雅
  • Aruforce 24天前
    引用 6
    无参过去应该不行…
  • Aruforce 24天前
    引用 7
    @Aruforce 无参获取
  • sutra 24天前
    引用 8
    https://www.baeldung.com/spring-security-async-principal-propagation
  • 楼主 dengji85 24天前
    引用 9
    @lance7in 谦虚了
  • 楼主 dengji85 24天前
    引用 10
    @sutra 项目是自己写的 filter,就是想实现他这个效果
  • dqzcwxb 24天前
    引用 11
    当成参数传递给异步线程,你用其他的方式也不过是 ThreadLocal 的变种
  • 楼主 dengji85 24天前
    引用 12
    @dqzcwxb 这样每个方法都得改参数
  • securityCoding 24天前
    引用 13
    我这边的方案是获取登录态信息只在 controller 层处理,往下层走的时候以方法参数的形式传过去。
    具体的流程是:
    1. 网关获取请求头中的 token,登录态 filter 解析 token ( isLogin,uid,uname,merchantId )设置到请求头。
    2. 网关带着登录态请求头转发请求。
    3. 底层服务从来不需要关注登录态,直接获取请求头即可。
  • securityCoding 24天前
    引用 14
    @dengji85 本身属于确定性的参数,就应该显示传
  • tsanie 24天前
    引用 15
    30 怕不是从肛门开始量(
  • hzz2 24天前
    引用 16
    现在问个问题都这么骚了吗
  • qwe520liao 24天前
    引用 17
    在同步编程模型下直接通过本地线程变量获取绑定的信息,相当于在这个线程上下文中设定了全局变量。

    使用同步编程模型,如果在 service 里面获取当前的信息,就跟使用 service 的环境耦合了(本地线程变量),service 不是无状态的。

    当然如果一直使用这种同步编程模型是没什么问题的,但如果想要在异步环境下不改变代码也可以使用 service 的话,就必须要在执行阶段先进行类似环境绑定的操作。

    比如在执行前,将之前的全局变量绑定到当前的线程,执行完以后再清除避免下一个执行任务获取到错误的信息。
  • CatKiller 24天前
    引用 18
    无 图 言 弔
  • 楼主 dengji85 24天前
    引用 19
    @hzz2 本想加个 D cup,但好像论坛没什么女大神把
  • bz5314520 24天前
    引用 20
    请求来的时候,自己包装个上下文呗。
  • liuqitoday 24天前
    引用 21
    与 12 楼一样,获取登录态信息只在 controller 层处理,往下层走的时候以方法参数的形式传过去
  • keshawnvan 24天前
    引用 22
    作为参数传过去,Service 层不应该感知登录态的。
  • vacuitym 24天前
    引用 23
    我们用 dubbo 的时候是放在上下文,然后拦截之后放在 threadlocal
  • yisheyuanzhang 24天前
    引用 24
    异步线程是如何创建的呢?线程池?
    我们项目使用的全局线程池,方案是线程池每次执行的时候都从父线程中把
    1 、Shiro/Spring security 当前用户 context 存放在 InheritableThreadLocal 中
    2 、 线程池内线程每次执行任务时都将父线程 InheritableThreadLocal 复制给池内子线程
    记了个笔记 https://zhaoydo.gitee.io/2020/08/26/thread-pool-thread-local/
  • ychost 24天前
    引用 25
    Service 层不应该主动感知用户信息,应该是 Controller 层感知到,然后传给 Service 层处理,
  • xuanbg 24天前
    引用 26
    拦截器或网关验证 token 的时候解析出来用户信息,然后放在请求头上面。Controller 里面取出来传给 Service 。
  • xuanbg 24天前
    引用 27
    @yisheyuanzhang InheritableThreadLocal 这种只适合单体架构,局限性比较大
  • aguesuka 24天前
    引用 28
    异步怎么实现的?成熟的同步或者异步方案都有 threadlocal 或者 context(vertx)。如果没有就自己实现一个。
  • RuzZ 24天前
    引用 29
    > InheritableThreadLocal 这种只适合单体架构,局限性比较大
    @xuanbg 没理解为什么说 InheritableThreadLocal 只适合单体架构,我的理解 InheritableThreadLocal 本质上就是创建线程时,会将父类的`inheritableThreadLocals`复制到子类的`inheritableThreadLocals`中,一个父子级线程可以传递的 threadLocal
  • xuanbg 24天前
    引用 30
    @RuzZ 不同机器还能传递?
  • 游客
    31
返回