Spring原理之spring session

随着Web应用向分布式集群发展,传统单机session管理已无法满足需求。SpringSession通过将session从容器中剥离并持久化至Redis、MongoDB或MySQL,提供了一种分布式session解决方案。本文详细介绍了SpringSession的工作原理,包括SessionRepositoryFilter、SessionRepository等关键组件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:

在传统的单机web应用之中,如使用tomcat时,session是由tomcat容器管理。容器根据浏览器cookie中的sessionID来判断session是否存在以及获取session。此时session是在单机的tomcat容器中,而随着单机web应用朝着分布式集群发展,此时用户的请求从浏览器可能会负载均衡分发到不同的应用中,传统的session管理方案已经不能满足需求了,此时需要一个分布式/集群的session解决方案,所以Spring session应运而生了。

工作原理:

spring session提供了一个SessionRepositoryFilter,用于装饰request与response,重写getSession等方法,从而使应用得到的session不再是tomcat容器中的session。Spring session将session从web容器中剥离,持久到redis mongo或者mysql中。
工作原理

接下来是关键类的介绍:

SessionRepositoryFilter

sessionRepositoryFilter基类的doFilter会调用下面这个方法,这里包装了原来的request与response

	@Override
	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
		//重新包装request与response
		SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(
				request, response, this.servletContext);
		SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(
				wrappedRequest, response);

		try {
			filterChain.doFilter(wrappedRequest, wrappedResponse);
		}
		finally {
			wrappedRequest.commitSession();
		}
	}

SessionRepositoryResponseWrapper的getSession方法

	@Override
		public HttpSessionWrapper getSession(boolean create) {
			HttpSessionWrapper currentSession = getCurrentSession();
			if (currentSession != null) {
				return currentSession;
			}
			//取本地缓存,如果没有则去sessionRepository中取
			S requestedSession = getRequestedSession();
			if (requestedSession != null) {
				if (getAttribute(INVALID_SESSION_ID_ATTR) == null) {
					requestedSession.setLastAccessedTime(Instant.now());
					this.requestedSessionIdValid = true;
					currentSession = new HttpSessionWrapper(requestedSession, getServletContext());
					currentSession.setNew(false);
					setCurrentSession(currentSession);
					return currentSession;
				}
			}
			else {
				// This is an invalid session id. No need to ask again if
				// request.getSession is invoked for the duration of this request
				if (SESSION_LOGGER.isDebugEnabled()) {
					SESSION_LOGGER.debug(
							"No session found by id: Caching result for getSession(false) for this HttpServletRequest.");
				}
				setAttribute(INVALID_SESSION_ID_ATTR, "true");
			}
			//取不到如果又不创建的话,就返回空
			if (!create) {
				return null;
			}
			if (SESSION_LOGGER.isDebugEnabled()) {
				SESSION_LOGGER.debug(
						"A new session was created. To help you troubleshoot where the session was created we provided a StackTrace (this is not an error). You can prevent this from appearing by disabling DEBUG logging for "
								+ SESSION_LOGGER_NAME,
						new RuntimeException(
								"For debugging purposes only (not an error)"));
			}
			//创建session,并放入sessionRepository
			S session = SessionRepositoryFilter.this.sessionRepository.createSession();
			session.setLastAccessedTime(Instant.now());
			currentSession = new HttpSessionWrapper(session, getServletContext());
			setCurrentSession(currentSession);
			return currentSession;
		}

SessionRepository

接口中主要有createSession、save、findById以及deleteById,SpringRepositoryFilter中内聚了这样的一个session仓库,这里如果我们使用springboot的话,我们创建一个SessionRepository这种类型的bean放入容器就可以了,常用的有MapSessionRepository以及RedisOperationSessionRepository,当然我们也可以自定义SessionRepository.
RedisHttpSessionConfiguration这个类是redis session的自动配置类,有兴趣的可以看看。

后面还剩一些session监听失效的内容,之后补上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值