V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dengji85
V2EX  ›  Java

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

  •  
  •   dengji85 · 2021-04-09 14:42:02 +08:00 · 4272 次点击
    这是一个创建于 1306 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    比如在执行前,将之前的全局变量绑定到当前的线程,执行完以后再清除避免下一个执行任务获取到错误的信息。
    CatKiller
        17
    CatKiller  
       2021-04-09 15:55:49 +08:00
    无 图 言 弔
    dengji85
        18
    dengji85  
    OP
       2021-04-09 16:24:24 +08:00
    @hzz2 本想加个 D cup,但好像论坛没什么女大神把
    bz5314520
        19
    bz5314520  
       2021-04-09 16:28:36 +08:00
    请求来的时候,自己包装个上下文呗。
    liuqitoday
        20
    liuqitoday  
       2021-04-09 17:10:20 +08:00   ❤️ 1
    与 12 楼一样,获取登录态信息只在 controller 层处理,往下层走的时候以方法参数的形式传过去
    keshawnvan
        21
    keshawnvan  
       2021-04-09 17:30:46 +08:00
    作为参数传过去,Service 层不应该感知登录态的。
    vacuitym
        22
    vacuitym  
       2021-04-09 17:34:14 +08:00
    我们用 dubbo 的时候是放在上下文,然后拦截之后放在 threadlocal
    yisheyuanzhang
        23
    yisheyuanzhang  
       2021-04-09 17:38:41 +08:00   ❤️ 1
    异步线程是如何创建的呢?线程池?
    我们项目使用的全局线程池,方案是线程池每次执行的时候都从父线程中把
    1 、Shiro/Spring security 当前用户 context 存放在 InheritableThreadLocal 中
    2 、 线程池内线程每次执行任务时都将父线程 InheritableThreadLocal 复制给池内子线程
    记了个笔记 https://zhaoydo.gitee.io/2020/08/26/thread-pool-thread-local/
    ychost
        24
    ychost  
       2021-04-09 17:45:18 +08:00
    Service 层不应该主动感知用户信息,应该是 Controller 层感知到,然后传给 Service 层处理,
    xuanbg
        25
    xuanbg  
       2021-04-09 22:06:55 +08:00
    拦截器或网关验证 token 的时候解析出来用户信息,然后放在请求头上面。Controller 里面取出来传给 Service 。
    xuanbg
        26
    xuanbg  
       2021-04-09 22:09:54 +08:00   ❤️ 1
    @yisheyuanzhang InheritableThreadLocal 这种只适合单体架构,局限性比较大
    aguesuka
        27
    aguesuka  
       2021-04-10 11:50:23 +08:00 via Android
    异步怎么实现的?成熟的同步或者异步方案都有 threadlocal 或者 context(vertx)。如果没有就自己实现一个。
    RuzZ
        28
    RuzZ  
       2021-04-14 17:27:27 +08:00
    > InheritableThreadLocal 这种只适合单体架构,局限性比较大
    @xuanbg 没理解为什么说 InheritableThreadLocal 只适合单体架构,我的理解 InheritableThreadLocal 本质上就是创建线程时,会将父类的`inheritableThreadLocals`复制到子类的`inheritableThreadLocals`中,一个父子级线程可以传递的 threadLocal
    xuanbg
        29
    xuanbg  
       2021-04-14 21:57:08 +08:00
    @RuzZ 不同机器还能传递?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3072 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 134ms · UTC 13:33 · PVG 21:33 · LAX 05:33 · JFK 08:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.