文章目录

  • 获取Subject
  • 猜想
  • 源码分析
  • ThreadContext是什么时候跟Subject绑定的呢?
  • 猜想ThreadLocal是跟当前线程绑定的,如果我springmvc里面使用异步方法执行,在异步处理过程中能获取到subject吗?
  • 验证:


获取Subject

使用shiro获取Subject的方法:

Subject subject = SecurityUtils.getSubject();

为什么,不管在哪通过SecurityUtils获取的Subject 都是同一个呢?
而且Subject 里面还有用户的信息.

猜想

首先,能在各个地方获取Subject 只有一种办法,就是通过ThreadLocal类来实现,那么SecurityUtils肯定维护了一个ThreadLocal.

源码分析

首先看getSubject方法:

通过SecurityUtils获取Subject详解_异步线程


点到ThreadContext类:

通过SecurityUtils获取Subject详解_spring_02


说明是ThreadContext类维护了一个ThreadLocal;

ThreadContext是什么时候跟Subject绑定的呢?

我们发现有个方法:bind(Subject subject),

看谁掉了这个方法:

通过SecurityUtils获取Subject详解_子线程_03


通过SecurityUtils获取Subject详解_异步线程_04


是SubjectCallable里面就开始绑定了,我们只要看是谁新建了SubjectCallable这个类就好了,发现在Subject里面执行execute的时候新建的,同时将subject也就是this传进去了.

通过SecurityUtils获取Subject详解_spring_05


现在明了了,上篇讲到subject创建详解 里面有一张图:

通过SecurityUtils获取Subject详解_异步线程_06


在创建了subject的时候就通过execute来执行过滤器链的方法,这时候将创建好的subject跟ThreadContext进行了绑定,所以我们在任何地方都可以通过SecurityUtils.getSubject()来获取Subject.

猜想ThreadLocal是跟当前线程绑定的,如果我springmvc里面使用异步方法执行,在异步处理过程中能获取到subject吗?

是可以的,我们看ThreadContext里的的ThreadLocal具体实现就知道了:

通过SecurityUtils获取Subject详解_异步线程_07


主要功劳就是InheritableThreadLocal实现,这个实现大概做的事情就是如果父线程里面使用ThreadLocal了,然后在父线程里面又创建子线程,这是会将父线程的ThreadLocal拷贝到子线程里面,所以在异步线程里面是可以获取到subject的.

这时候就会想如果是异步线程池呢,这一块比较复杂,因为

InheritableThreadLocal实现的时候,如果是异步线程池,在一开始设置了ThreadLocal,他是有缓存的,详情见:解决父子线程ThreadLocal中的缓存问题

验证:

通过SecurityUtils获取Subject详解_子线程_08