各位 30cm, 问一下 所谓的 service 层中怎么优雅获取当前用户 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dengji85
V2EX    Java

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

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

    以前一直习惯用 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     Solana     2523 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 15:03 PVG 23:03 LAX 08:03 JFK 11:03
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86