栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Session 的原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Session 的原理

原文地址: Spring Session 的原理

欢迎访问我的博客: https://blog.duhbb.com


引言

今天在写一个对外接口, 这个接口大致原理是在过滤器中通过 token 获取用户信息然后创建 session, 后续的流程就是 Controller -> Service -> Dao 了.

这次开发没有像之前那样愣头愣脑的, 我想了一下, 对方调用的时候是没有 session id 的, 也就是每次认证之后都会创建一个 session. 那这就可能存在一个大问题了, 假设调用次数非常多的话, 会创建茫茫多的 session, 可能会击垮系统.

所以我的看下我们系统中是如何使用 session 的.

Spring Session 探索 代码跟踪

第一件做的是就是断点 request 获取 session 的代码, 果然是有说法啊!

request.getSession()

file

@SuppressWarnings("deprecation")
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
public class SessionRepositoryFilter extends OncePerRequestFilter {
	public static final String SESSION_REPOSITORY_ATTR = SessionRepository.class.getName();

	public static final int DEFAULT_ORDER = Integer.MIN_VALUE + 50;

	private final SessionRepository sessionRepository;

	private ServletContext servletContext;

	private MultiHttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy();

file

public void setAttribute(String name, Object value) {
	// 还挺讲究的, 设置 attr 之前先 checkState
	checkState();
	session.setAttribute(name, value);
}

checkState() 也很简单, 就是校验 invalidated 是否为 true.

private void checkState() {
	if(invalidated) {
		throw new IllegalStateException("The HttpSession has already be invalidated.");
	}
}

光从代码找还是有点难找的, 不过还是找到了:

file

file

file

验证 redis 中的数据

上个 debug 的 session 的 key 是: spring:session:sessions:62359810-d2cb-4378-a619-e2c31bb8242c, 看上去是存了一个 hash 结构.

redis 中获取 hash 的命令是:

HGETALL hkey

执行一下:

127.0.0.1:6379> HGETALL spring:session:sessions:62359810-d2cb-4378-a619-e2c31bb8242c
1) "maxInactiveInterval"
2) "xacxedx00x05srx00x11java.lang.Integerx12xe2xa0xa4xf7x81x878x02x00x01Ix00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x01Qx80"
3) "lastAccessedTime"
4) "xacxedx00x05srx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x01x82x00:x99x0e"
5) "creationTime"
6) "xacxedx00x05srx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x01x82x00:x99x0e"

里面好像还是没有业务数据, 艹, 发现我傻逼了, 断点还没放开,redis 压根还没存这个业务数据.

再执行一遍:

127.0.0.1:6379> HGETALL spring:session:sessions:62359810-d2cb-4378-a619-e2c31bb8242c
 1) "creationTime"
 2) "xacxedx00x05srx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x01x82x00:x99x0e"
 3) "lastAccessedTime"
 4) "xacxedx00x05srx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x01x82x00Dx1f["
 5) "sessionAttr:HumanSession"
 6) "xacxedx00x05srx00#cn.com.xxx.base.bean.HumanSessionx8fxbbxb6dxf6x04x8axd5x02x00x1fDx00x0bcoordinateXDx00x0bcoordinateYZx00tvalidFlagLx00x0fautoReceiveFlagtx00x13Ljava/lang/Integer;Lx00x0ebrowserVersiontx00x12Ljava/lang/String;Lx00ndataUnitIDqx00~x00x01Lx00afromCasqx00~x00x01Lx00tfromTokenqx00~x00x01Lx00thumanCodeqx00~x00x02Lx00ahumanIDqx00~x00x01Lx00thumanNameqx00~x00x02Lx00nhumanStyleqx00~x00x02Lx00ninvalidMsgqx00~x00x02Lx00x02ipqx00~x00x02Lx00rleaderLevelIDqx00~x00x01Lx00x05logIDqx00~x00x01Lx00tosVersionqx00~x00x02Lx00npatrolFlagqx00~x00x01Lx00bportraitqx00~x00x02Lx00bproxyUrlqx00~x00x02Lx00nregionCodeqx00~x00x02Lx00bregionIDqx00~x00x01Lx00nregionNameqx00~x00x02Lx00nregionTypeqx00~x00x01Lx00bserverIpqx00~x00x02Lx00x06targetqx00~x00x02Lx00ttelMobileqx00~x00x02Lx00aunionIDqx00~x00x01Lx00x06unitIDqx00~x00x01Lx00bunitNameqx00~x00x02Lx00buserNameqx00~x00x02xpx00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x01pppsrx00x11java.lang.Integerx12xe2xa0xa4xf7x81x878x02x00x01Ix00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x00x00qx00~x00x06tx00rwizdom:100433sqx00~x00x04x00x01x88Qtx00x05xxxxxx00bdarkblueptx00x0f192.168.213.161pppqx00~x00x06tx00x00ppqx00~x00x06psqx00~x00x04x00x00x00x01tx00t127.0.0.1ptx00x0b17700000000sqx00~x00x04x00x00x02xbesqx00~x00x04x00x00x00x02tx00x0fxe5xb8x82xe7x9bx91xe7x9dxa3xe4xb8xadxe5xbfx83tx00x05xxx"
 7) "maxInactiveInterval"
 8) "xacxedx00x05srx00x11java.lang.Integerx12xe2xa0xa4xf7x81x878x02x00x01Ix00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x01Qx80"
 9) "sessionAttr:UnionAuthToken"
10) "xacxedx00x05tx00$125ba47c-fe01-42b6-b5a2-8a87eb266ddc"

这回有了, 而且还很多.

过期时间如何设置呢?

其实在可以加一个过滤器, 像平常那样设置 session 的过期时间就行:

req.getSession().setMaxInactiveInterval(expireTime);
filterChain.doFilter(servletRequest, servletResponse);
session 存储的小结

Spring Session 对 JavaWeb 中的 session 进行了一层包装, 写业务时候的接口都保持不变, 但是底层的存储从 Tomcat 中的内存变成了 Redis, 而且用户还没有感知.

如果可以能用哨兵模式保证 Redis 的高可以, 感觉是不是就解决了分布式 Session 的问题.

Session 的 invalidate 实现
HttpSession session = request.getSession();
if(session != null){
	session.removeAttribute();
	session.invalidate();
}

看来这里主要就是 session.invalidate() 了.

// org.springframework.session.web.http.SessionRepositoryFilter.SessionRepositoryRequestWrapper.
// HttpSessionWrapper#invalidate
public void invalidate() {
	checkState();
	this.invalidated = true;
	requestedSessionInvalidated = true;
	setCurrentSession(null);
	sessionRepository.delete(getId());
}

根据 id 删除 session:

// org.springframework.session.data.redis.RedisOperationsSessionRepository#delete
public void delete(String sessionId) {
	ExpiringSession session = getSession(sessionId, true);
	if(session == null) {
		return;
	}

	String key = getKey(sessionId);
	expirationPolicy.onDelete(session);

	// always delete they key since session may be null if just expired
	this.sessionRedisOperations.delete(key);
}

onDelete 中也删除数据的:

	public void onDelete(ExpiringSession session) {
		long toExpire = roundUpToNextMinute(expiresInMillis(session));
		String expireKey = getExpirationKey(toExpire);
		expirationRedisOperations.boundSetOps(expireKey).remove(session.getId());
	}
盗来的一张图

file

回到我的问题

第三方通过 token 调用接口创建会话的问题很简单, 调用完了之后就可以将 session invalidate 了.

哈哈


原文地址: Spring Session 的原理

欢迎访问我的博客: https://blog.duhbb.com

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号