1、代码实现
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
</dependencies>
简例:
@RestController
@RequestMapping(value = "/session")
public class SessionShareController {
@Value("${server.port}")
Integer port;
@GetMapping(value = "/set")
public String set(HttpSession session){
session.setAttribute("user","wangwq8");
return String.valueOf(port);
}
@GetMapping(value = "get")
public String get(HttpSession session){
return "用户:"+session.getAttribute("user")+",端口:"+port;
}
}
结果:
2、Spring session整个实现流程和源码详细介绍
主要两个配置类RedisHttpSessionConfiguration和SpringHttpSessionConfiguration
查看@EnableRedisHttpSession
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ java.lang.annotation.ElementType.TYPE })
@Documented
@Import(RedisHttpSessionConfiguration.class)
@Configuration
public @interface EnableRedisHttpSession {
...
}
查看RedisHttpSessionConfiguration
主要就是将操纵redis的redisTemplate放入sessionRepository中,而sessionRepository中统一规定了获取session的方法名。即可通过sessionRepository从redis里获取session。
@Configuration
@EnableScheduling
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
implements EmbeddedValueResolverAware, ImportAware {
...
}
发现其继承自SpringHttpSessionConfiguration查看
- 发现其session默认的策略是使用 defaultHttpSessionStrategy=new CookieHttpSessionStrategy();cookie来实现
public class SpringHttpSessionConfiguration implements ApplicationContextAware {
private CookieHttpSessionStrategy defaultHttpSessionStrategy = new CookieHttpSessionStrategy();
private boolean usesSpringSessionRememberMeServices;
private ServletContext servletContext;
private CookieSerializer cookieSerializer;
private HttpSessionStrategy httpSessionStrategy = this.defaultHttpSessionStrategy;
private List<HttpSessionListener> httpSessionListeners = new ArrayList<HttpSessionListener>();
@PostConstruct
public void init() {
if (this.cookieSerializer != null) {
this.defaultHttpSessionStrategy.setCookieSerializer(this.cookieSerializer);
}
else if (this.usesSpringSessionRememberMeServices) {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setRememberMeRequestAttribute(
SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR);
this.defaultHttpSessionStrategy.setCookieSerializer(cookieSerializer);
}
}
@Bean
public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() {
return new SessionEventHttpSessionListenerAdapter(this.httpSessionListeners);
}
@Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(
SessionRepository<S> sessionRepository) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(
sessionRepository);
sessionRepositoryFilter.setServletContext(this.servletContext);
if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) {
sessionRepositoryFilter.setHttpSessionStrategy(
(MultiHttpSessionStrategy) this.httpSessionStrategy);
}
else {
sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy);
}
return sessionRepositoryFilter;
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
if (ClassUtils.isPresent(
"org.springframework.security.web.authentication.RememberMeServices",
null)) {
this.usesSpringSessionRememberMeServices = !ObjectUtils
.isEmpty(applicationContext
.getBeanNamesForType(SpringSessionRememberMeServices.class));
}
}
@Autowired(required = false)
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
@Autowired(required = false)
public void setCookieSerializer(CookieSerializer cookieSerializer) {
this.cookieSerializer = cookieSerializer;
}
@Autowired(required = false)
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
this.httpSessionStrategy = httpSessionStrategy;
}
@Autowired(required = false)
public void setHttpSessionListeners(List<HttpSessionListener> listeners) {
this.httpSessionListeners = listeners;
}
}
单看springSessionRepositoryFilter方法
这里生成了一个SessionRepositoryFilter过滤器,并将上一个配置类中的sessionRepository放入到这个过滤器中。所以这个过滤器就是替换服务器session的关键。
- 传入参数SessionRepository的实现类RedisOperationsSessionRepository在RedisHttpSessionConfiguration被进行创建所以sessionRepository使用的就是RedisOperationsSessionRepository用来做于存储
@Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(
SessionRepository<S> sessionRepository) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(
sessionRepository);
sessionRepositoryFilter.setServletContext(this.servletContext);
if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) {
sessionRepositoryFilter.setHttpSessionStrategy(
(MultiHttpSessionStrategy) this.httpSessionStrategy);
}
else {
sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy);
}
return sessionRepositoryFilter;
}
当执行过滤器
@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);
HttpServletRequest strategyRequest = this.httpSessionStrategy
.wrapRequest(wrappedRequest, wrappedResponse);
HttpServletResponse strategyResponse = this.httpSessionStrategy
.wrapResponse(wrappedRequest, wrappedResponse);
try {
filterChain.doFilter(strategyRequest, strategyResponse);
}
finally {
wrappedRequest.commitSession();
}
}
- 这个doFilterInternal方法重写的是OncePerRequestFilter抽象类的方法,而OncePerRequestFilter实现的是Filter接口,在doFilter方法中会调用doFilterInternal。
- 这里先是将sessionRepository放入到了request的attribute中,然后又用框架中的类SessionRepositoryRequestWrapper对request进行了封装。这个类里有利用sessionRepository创建,获取,删除session的方法。
- 同时对response也进行了封装