springboot はセッションを統合してセッション共有を実現します

序文

セッションと Cookie はユーザー状態を保存する 2 つの方法であり、セッションはサーバー側にあり、Cookie はクライアント側にあります。
この記事では、springboot 統合セッションのデモ例を記録します。

セッション(セッション)

  • スティッキーセッション
    サーバーがダウンすると、セッション情報が失われます。
  • レプリケーションセッション
    各マシンがセッションをレプリケートしますが、量が大きすぎると現実的ではありません
  • セッションを集中させる
    mongo、redisなどを利用してセッションを均一に維持する

pom 依存関係

	<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

スタートアップクラス

@SpringBootApplication
@RestController
@EnableRedisHttpSession
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(SessionDemoApplication.class, args);
	}
	@RequestMapping("/hello")
	public String printSession(HttpSession session, String name) {
		String storedName = (String) session.getAttribute("name");
		if (storedName == null) {
			session.setAttribute("name", name);
			storedName = name;
		}
		return "hello " + storedName;
	}

}

@EnableRedisHttpSession このアノテーションを使用して、httpsession redis の自動構成を有効にします。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(RedisHttpSessionConfiguration.class)
@Configuration
public @interface EnableRedisHttpSession {
}

次に、RedisHttpSessionConfiguration を見てください。

@Configuration
@EnableScheduling
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
		implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware,
		SchedulingConfigurer {

	static final String DEFAULT_CLEANUP_CRON = "0 * * * * *";

	private Integer maxInactiveIntervalInSeconds = MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS;

	private String redisNamespace = RedisOperationsSessionRepository.DEFAULT_NAMESPACE;

	private RedisFlushMode redisFlushMode = RedisFlushMode.ON_SAVE;

	private String cleanupCron = DEFAULT_CLEANUP_CRON;

	private ConfigureRedisAction configureRedisAction = new ConfigureNotifyKeyspaceEventsAction();

	private RedisConnectionFactory redisConnectionFactory;

	private RedisSerializer<Object> defaultRedisSerializer;

	private ApplicationEventPublisher applicationEventPublisher;

	private Executor redisTaskExecutor;

	private Executor redisSubscriptionExecutor;

	private ClassLoader classLoader;

	private StringValueResolver embeddedValueResolver;
	...

Redis のいくつかの構成が実装されており、RedisHttpSessionConfiguration が SpringHttpSessionConfiguration を継承していることがわかります。そのため、このクラスのソース コードを見てください。

@Configuration
public class SpringHttpSessionConfiguration implements ApplicationContextAware {

	private final Log logger = LogFactory.getLog(getClass());

	private CookieHttpSessionIdResolver defaultHttpSessionIdResolver = new CookieHttpSessionIdResolver();

	private boolean usesSpringSessionRememberMeServices;

	private ServletContext servletContext;

	private CookieSerializer cookieSerializer;

	private HttpSessionIdResolver httpSessionIdResolver = this.defaultHttpSessionIdResolver;

	private List<HttpSessionListener> httpSessionListeners = new ArrayList<>();

	@PostConstruct
	public void init() {
		CookieSerializer cookieSerializer = (this.cookieSerializer != null)
				? this.cookieSerializer
				: createDefaultCookieSerializer();
		this.defaultHttpSessionIdResolver.setCookieSerializer(cookieSerializer);
	}

	@Bean
	public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() {
		return new SessionEventHttpSessionListenerAdapter(this.httpSessionListeners);
	}

	@Bean
	public <S extends Session> SessionRepositoryFilter<? extends Session> springSessionRepositoryFilter(
			SessionRepository<S> sessionRepository) {
		SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<>(
				sessionRepository);
		sessionRepositoryFilter.setServletContext(this.servletContext);
		sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver);
		return sessionRepositoryFilter;
	}
......

SpringHttpSessionConfiguration も構成クラスであり、いくつかの Bean を登録します。このフィルター Bean SessionRepositoryFilterを見てみましょう

@Order(SessionRepositoryFilter.DEFAULT_ORDER)
public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFilter {
...
	@Override
	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);

		SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(
				request, response, this.servletContext);
		SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(
				wrappedRequest, response);

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

...
}


abstract class OncePerRequestFilter implements Filter {

}

SessionRepositoryFilter が OncePerRequestFilter を継承し、フィルター フィルターを実装していることがわかります。
リクエストを一度カプセル化する doFilterInternal メソッドを見てみましょう。

		private SessionRepositoryRequestWrapper(HttpServletRequest request,
				HttpServletResponse response, ServletContext servletContext) {
			super(request);
			this.response = response;
			this.servletContext = servletContext;
		}

		@Override
		public HttpSessionWrapper getSession(boolean create) {
			HttpSessionWrapper currentSession = getCurrentSession();
			if (currentSession != null) {
				return currentSession;
			}
			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)"));
			}
			S session = SessionRepositoryFilter.this.sessionRepository.createSession();
			session.setLastAccessedTime(Instant.now());
			currentSession = new HttpSessionWrapper(session, getServletContext());
			setCurrentSession(currentSession);
			return currentSession;
		}

getSeesion メソッドも SessionRepositoryRequestWrapper で提供されており、セッションを取得するロジックはここにあります。SessionRepositoryFilter.this.sessionRepository.createSession() のメソッドを見てみましょう: その
実装をクリックします。

	@Override
	public RedisSession createSession() {
		RedisSession redisSession = new RedisSession();
		if (this.defaultMaxInactiveInterval != null) {
			redisSession.setMaxInactiveInterval(
					Duration.ofSeconds(this.defaultMaxInactiveInterval));
		}
		return redisSession;
	}

redisを使用していることが分かりました。この時点で、redis をセッションとして使用するプロセスは基本的に完了します。


次に、http://localhost:8080/hello?name=springにアクセスする
ここに画像の説明を挿入
と、最初のリクエストの応答ヘッダーでセッションが返され、結果が返されることがわかります。

hello spring

名前を変更して試してみると、
ここに画像の説明を挿入
Response ヘッダーには set-cookies がなく、リクエスト ヘッダーには Cookie 情報があることがわかりました。そして返される結果は変わりません:

hello spring

レディス

Redis を確認してください。Redis の実行には docker を使用しています

> docker exec -it redis bash
> redis-cli
> keys *
 1) "spring:session:expirations:1560958020000"
 2) "spring:session:expirations:1560958140000"
 3) "spring:session:sessions:51ffe6c7-9007-4ab9-9e90-0767189e5bf7"
 4) "spring:session:sessions:056a46cf-2fbc-4f33-ace3-46d5122177eb"
 5) "spring:session:sessions:expires:51ffe6c7-9007-4ab9-9e90-0767189e5bf7"
 6) "spring:session:sessions:0fe747b1-691a-4ddf-93f1-8e0a5e538c71"
 7) "spring:session:sessions:expires:056a46cf-2fbc-4f33-ace3-46d5122177eb"
 8) "spring:session:sessions:expires:0fe747b1-691a-4ddf-93f1-8e0a5e538c71"

> hkeys "spring:session:sessions:0fe747b1-691a-4ddf-93f1-8e0a5e538c71"
1) "sessionAttr:name"
2) "creationTime"
3) "lastAccessedTime"
4) "maxInactiveInterval"

Redis ツール rdb を使用して表示します。
ここに画像の説明を挿入
この記事はこれで終わりです。

おすすめ

転載: blog.csdn.net/wjavadog/article/details/92851531