Shiro源代码分析之两种Session的方式
1、Shiro默认的Session处理方式
<!-- 定义 Shiro 主要业务对象 --> |
这里从DefaultWebSecurityManager这里看起。这个代码是定义的Shiro安全管理对象,看以下的构造方法(代码
1-1)
|
(代码 1-1) public DefaultWebSecurityManager() {
|
从 构造方法里面能够看出,这里面有 publicvoid setRememberMeManager(RememberMeManager rememberMeManager)
和 publicvoid setSessionManager(SessionManager sessionManager)两个方法。这两个各自是对Shiro的remembereMe功能和Session功能的管理。当中在构造方法里面能够看到,事实上一开是就设置了SessionManager。就是默认的:ServletContainerSessionManager().接下来看看默认的ServletContainerSessionManager()是怎么玩转Session的.看下图。这个图显示了这个类的这些个方法
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
这个类通过getSession(SessionKey)获得Sesison,以下看看这种方法干了些什么(代码1-2)
|
(代码1-2) publicSession getSession(SessionKey key) throws SessionException { if (!WebUtils.isHttp(key)) { //推断是不是http的key,否则抛异常
|
能够看看凝视,凝视上都写好了。这里的意思是。首先推断封装好的Key是不是Http的key。假设是就继续,不是就抛异常.key这个是带了ServletRequest和ServletResponse的WebSessinKey,详细怎么new出来的,看DefaultWebSecurityManager的这方法代码就知道了(代码1-3)。这里里,将Request和Response还有sessionId传递进去
|
(代码1-3) @Override protected SessionKey getSessionKey(SubjectContext context) {
|
由于继承了 org.apache.shiro.session.mgt.DefaultSessionKey ,这个类是实现了SessionKey这个接口。 看看createSession这种方法,这种方法就是将传入的HttpSession和host传进去,封装成Shiro的HttpServletSession (代码 1-4)
|
(代码1-4) protectedSession createSession(HttpSession httpSession, String host) { return new HttpServletSession(httpSession, host); |
关于默认的Session管理器,最后还看一下HttpServletSession这个类。就看一下的几个方法。还有些方法是没有放出来的,能够明显的看出。Shiro使用了一个叫Session的接口。但这个接口是和HttpSession的接口一模一样。就是通过HttpSession这个接口获得Session的功能(代码1-5)
|
(代码1-5) public class HttpServletSession implements Session {
|
默认的模式就描写叙述到这里
2、接下来说另外一种方式。就是废弃掉tomcat自己的Session,使用企业级Session方案。这样的方案能够和容器无关。但在我们项目没有使用,由于用了开源连接池druid貌似logout的时候有点不正确。
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="globalSessionTimeout" value="3600000" />
<property name="sessionDAO" ref="sessionDAO" />
</bean>
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
<property name="activeSessionsCacheName" value="shiro-activeSessionCache" />
<property name="cacheManager" ref="shiroCacheManager" />
</bean> <!-- 用户授权信息Cache, 採用EhCache -->
<bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="cacheManager"/>
</bean>
必须向Spring注冊EnterpriseCacheSessionDAO然后将cacheManager注入进去
这样的配置的创建入口在SecurityUtils.getSubject().getSession();这里看以下代码(代码2-1)
|
(代码2-1) publicSession getSession(boolean create) { if (log.isTraceEnabled()) {
|
调用DefaultSecurityManager的父类SessionsSecurityManager的Sessionstart(SessionContext
context)。以下是这种方法的代码(代码2-2)
|
(代码2-2) public Session start(SessionContext context) throws AuthorizationException {
|
然后调用sessionManager的start方法来创建Session。创建Session的入口。就在这里。看以下代码分析(代码2-3)
|
(代码2-3) publicSession start(SessionContext context) { Session session = createSession(context);//创建Session |
创建Session这里是调用DefaultSessionManager的父类的createSession,事实上父类也没有真正来创建Session。
这里用到了模板方法。父类里面的doCreateSession是抽象方法,最后真正创建子类的还是交给子类去实现(代码2-4)
|
(代码2-4) protectedSession createSession(SessionContext context) throwsAuthorizationException { enableSessionValidationIfNecessary(); |
其它的也没多少可分析的。这里再看一下manager里面的sessionFacotry工厂的createSession方法(代码2-5)
|
(代码2-5) publicSession createSession(SessionContext initData) { if (initData != null) {
|
这里的SimpleSession是实现了Session接口的。详细能够看看相关的类继承图
另外Session是怎么缓存进入Cache的呢?在以下的调用以下代码创建Session的过程中,以下方法会调用,而缓存就在create(s)这里面(代码2-6)
|
(代码2-6) protected Session doCreateSession(SessionContext context) {
|
经过一些步骤之后在CachingSessionDao里被缓存,以下是代码。
能够看以下的凝视(代码2-7)
|
(代码2-7) protectedvoid cache(Session session, Serializable sessionId) { if (session == null || sessionId == null) {
|
以上是Session的创建过程,获取Session就简单说吧。有些过程自己发现更有趣。这里会调用DefaultWebSessionManager的父类的getAttribute这种方法(代码2-8)
|
(代码2-8) publicObject getAttribute(SessionKey sessionKey, Object attributeKey)throws InvalidSessionException { return lookupRequiredSession(sessionKey).getAttribute(attributeKey); |
最后会调用CachingSessionDao的这个publicSession readSession(Serializable
sessionId) throwsUnknownSessionException 在这里就会从缓存里读取Session(代码2-9)
|
(代码2-9) public Session readSession(Serializable sessionId) throws UnknownSessionException {
|
这是getCachedSession(sessionId)的代码。看了代码想必非常easy理解了吧(代码2-10)
protected Session getCachedSession(Serializable sessionId) {
|
获得了Session,要获得里面的值和对象就非常easy了
有问题欢迎提出来。由于是先写在编辑器上的。然后在复制到word上。所以代码是一致的黑色,希望可以讲究着看,写个原创文章不easy,眼睛都看肿了。所以转载的时候能带上作者,谢谢
作者:肖华
blog.csdn.net/xh199110
飞丶天
Shiro源代码分析之两种Session的方式的更多相关文章
- 牛客网Java刷题知识点之Map的两种取值方式keySet和entrySet、HashMap 、Hashtable、TreeMap、LinkedHashMap、ConcurrentHashMap 、WeakHashMap
不多说,直接上干货! 这篇我是从整体出发去写的. 牛客网Java刷题知识点之Java 集合框架的构成.集合框架中的迭代器Iterator.集合框架中的集合接口Collection(List和Set). ...
- 关于VAD的两种内存隐藏方式
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 技术学习来源:火哥(QQ:471194425) 内存在0环的两种内 ...
- Windows Azure VM的两种shut down 方式
今天在调查Azure的价格时,发现下面的语句,来自http://azure.microsoft.com/en-us/pricing/details/virtual-machines/ * If my ...
- 两种隐藏元素方式【display: none】和【visibility: hidden】的区别
此随笔的灵感来源于上周的一个面试,在谈到隐藏元素的时候,面试官突然问我[display: none]和[visibility: hidden]的区别,我当时一愣,这俩有区别吗,好像有,但是忘记了啊,因 ...
- Linux共享库两种加载方式简述
Linux共享库两种加载方式简述 动态库技术通常能减少程序的大小,节省空间,提高效率,具有很高的灵活性,对于升级软件版本也更加容易.与静态库不同,动态库里面的函数不是执行程序本身 的一部分,而是 ...
- android环境下两种md5加密方式
在平时开发过程中,MD5加密是一个比较常用的算法,最常见的使用场景就是在帐号注册时,用户输入的密码经md5加密后,传输至服务器保存起来.虽然md5加密经常用,但是md5的加密原理我还真说不上来,对md ...
- Form表单中method=post/get两种数据传输的方式的区别
Form提供了两种数据传输的方式——get和post.虽然它们都是数据的提交方式,但是在实际传输时确有很大的不同,并且可能会对数据产生严重的影响.虽然为了方便的得到变量值,Web容器已经屏蔽了二者的一 ...
- 两种数据传输的方式——get和post。
Form提供了两种数据传输的方式——get和post.虽然它们都是数据的提交方式,但是在实际传输时确有很大的不同,并且可能会对数据产生严重的影响.虽然为了方便的得到变量值,Web容器已经屏蔽了二者的一 ...
- Xamarin Android Fragment的两种加载方式
android Fragment的重点: 3.0版本后引入,即minSdk要大于11 Fragment需要嵌套在Activity中使用,当然也可以嵌套到另外一个Fragment中,但这个被嵌套的Fra ...
随机推荐
- HDU-1009-肥鼠交易
这题是一道简单的可拆分的贪心题目,需要注意的是,我们定义的结构体里面都应该用double类型, 或者float类型,不然两个int相除,就失去了精度(强转也可以). #include <cstd ...
- (22)zabbix触发器依赖关系详解
概述 zabbix触发器可以设置依赖性,例如我配置了两个触发器,一个触发器定义www.ttlsa.com这个HOST是否在运行中,另一个是www.ttlsa.com的网络是否通畅. 假如网络出现故障, ...
- Git学习——从远程库克隆
克隆一个本地库 首先准备好一个远程库.再用命令克隆一个本地库. git clone git@github.com:<github账户>/<远程库名>.git 克隆一个仓库,首先 ...
- jQuery实现Ajax
jQuery.ajax([settings]) type:类型,“POST”或“GET”,默认为GET url:发送地址 data:连同请求发送到服务器的数据 dataType:预期服务器返回的数据类 ...
- perl学习之六:变量作用域
变量作用域 (一)包变量 $x = 1 这里,$x是个包变量.关于包变量,有2件重要的事情要了解: 1)假如没有其他申明,变量就是包变量:2)包变量总是全局的. 全局意味着包变量在每个程序里总可访问到 ...
- linux下mysql常用的基本命令
linux数据库环境搭建好之后,我们就可以创建数据库了. 一 查看版本 mysql --version 二 进入数据库 首先在根目录执行命令 mysql -u root -p 然后输入密码 进 ...
- python--subprocess,粘包现象与解决办法,缓冲区
一. subprocess 的简单用法 import subprocess sub_obj = subprocess.Popen( 'dir', #系统指令 shell=True, #固定方法 std ...
- shell-code-2-传参
#在执行shell脚本时,带参数,如./test.sh 1 2 3,则在脚本test.sh内,参数表示为$n的形式,$1为第一个参数,以此类推. echo "第一个参数为:$1"; ...
- python中split()函数讲解
本文讲述的是string.split(s[, sep[, maxsplit]]),针对string类型的split()函数.它主要是切割字符串,结果返回由字符串元素组成的一个列表,具体怎么使用看下面的 ...
- luogu1231 教辅的组成
注意把书拆成两份 #include <iostream> #include <cstring> #include <cstdio> #include <que ...