# WebSession 集成

Spring Session 提供了与 Spring WebFlux 的`WebSession`的透明集成。这意味着你可以使用 Spring Session 支持的实现来切换`WebSession`实现。

## 为什么要进行会话和 WebSession？

我们已经提到， Spring Session 提供了与 Spring WebFlux 的`WebSession`的透明集成，但是我们从中得到了什么好处呢？与`HttpSession`一样， Spring Session 使得在不绑定到特定于应用程序容器的解决方案的情况下支持[群集会话](#websession-redis)变得非常简单。

## 与 Redis 的 WebSession

使用 Spring session with`WebSession`是通过注册一个`WebSessionManager`实现来启用的，该实现由 Spring session 的`ReactiveSessionRepository`支持。 Spring 配置负责创建一个`WebSessionManager`，该实现用 Spring Session 支持的实现替换`WebSession`实现。要做到这一点，请添加以下 Spring 配置：

```
@EnableRedisWebSession (1)
public class SessionConfiguration {

	@Bean
	public LettuceConnectionFactory redisConnectionFactory() {
		return new LettuceConnectionFactory(); (2)
	}

}
```

|**1**|`@EnableRedisWebSession`注释创建了一个名为`webSessionManager`的 Spring  Bean。这个 Bean 实现了`WebSessionManager`。<br/>这就是负责替换要由 Spring Session 支持的`WebSession`实现的内容。<br/>在这个实例中， Spring Session 是由 Redis 支持的。|
|-----|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|我们创建一个`RedisConnectionFactory`将 Spring Session 连接到 Redis 服务器。<br/>我们将连接配置为在默认端口（6379）<br/>上连接到 localhost。有关配置 Spring 数据 Redis 的更多信息，请参见[参考文献](https://docs.spring.io/spring-data/data-redis/docs/2.6.2/reference/html/)。|

## WebSession 集成如何工作

与 Servlet API 及其`HttpSession`相比， Spring Session 与 Spring WebFlux 及其`WebSession`集成要容易得多。 Spring WebFlux 提供了`WebSessionStore`API，该 API 提供了用于持久化`WebSession`的策略。

|   |本节描述 Spring Session 如何使用`WebSession`提供透明的集成。我们提供这些内容，这样你就可以了解幕后发生了什么。这个功能已经集成了，你不需要自己实现这个逻辑。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

首先，我们创建一个自定义的`SpringSessionWebSession`，它将委托给 Spring Session 的`Session`。它看起来是这样的：

```
public class SpringSessionWebSession implements WebSession {

	enum State {
		NEW, STARTED
	}

	private final S session;

	private AtomicReference<State> state = new AtomicReference<>();

	SpringSessionWebSession(S session, State state) {
		this.session = session;
		this.state.set(state);
	}

	@Override
	public void start() {
		this.state.compareAndSet(State.NEW, State.STARTED);
	}

	@Override
	public boolean isStarted() {
		State value = this.state.get();
		return (State.STARTED.equals(value)
				|| (State.NEW.equals(value) && !this.session.getAttributes().isEmpty()));
	}

	@Override
	public Mono<Void> changeSessionId() {
		return Mono.defer(() -> {
			this.session.changeSessionId();
			return save();
		});
	}

	// ... other methods delegate to the original Session
}
```

接下来，我们创建一个自定义`WebSessionStore`，它将委托给`ReactiveSessionRepository`，并将`Session`封装到自定义`WebSession`实现中，如下所示：

```
public class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore {

	private final ReactiveSessionRepository<S> sessions;

	public SpringSessionWebSessionStore(ReactiveSessionRepository<S> reactiveSessionRepository) {
		this.sessions = reactiveSessionRepository;
	}

	// ...
}
```

要被 Spring WebFlux 检测到，此自定义`WebSessionStore`需要在`ApplicationContext`中注册为 Bean 名为`webSessionManager`的 Bean。有关 Spring WebFlux 的更多信息，请参见[Spring Framework Reference Documentation](https://docs.spring.io/spring-framework/docs/5.3.16/reference/html/web-reactive.html)。