Я хотел обновить свой проект Spring Webflux с Spring Boot 2.0.1 до Spring Boot 2.0.3. В моем проекте мои сессии поддерживаются Red Session Data Redis. При обновлении версии Spring Boot я заметил проблему аннулирования веб-сессий в Spring Boot 2.0.2 +.
В Spring Boot 2.0.1 я аннулировал свои сессии следующим образом:
webSession.invalidate().subscribe();
Это привело к уничтожению моего текущего сеанса, и был создан новый сеанс с новым идентификатором сеанса, временем создания и т. Д.
Тем не менее, начиная с Spring Boot 2.0.2, тот же код, по-видимому, не полностью разрушает сеанс. Информация о текущем сеансе просто «очищается», и тот же идентификатор сеанса все еще используется впоследствии. Это проблема, потому что она вызывает исключение пустого указателя в ReactiveRedisOperationsSessionRepository.class :
private static final class SessionMapper implements Function<Map<String, Object>, MapSession> {
private final String id;
private SessionMapper(String id) {
this.id = id;
}
public MapSession apply(Map<String, Object> map) {
MapSession session = new MapSession(this.id);
session.setCreationTime(Instant.ofEpochMilli((Long)map.get("creationTime")));
session.setLastAccessedTime(Instant.ofEpochMilli((Long)map.get("lastAccessedTime")));
session.setMaxInactiveInterval(Duration.ofSeconds((long)(Integer)map.get("maxInactiveInterval")));
map.forEach((name, value) -> {
if (name.startsWith("sessionAttr:")) {
session.setAttribute(name.substring("sessionAttr:".length()), value);
}
});
return session;
}
}
Поскольку данные сеанса пусты (без времени создания и т. Д.), Следующая строка вызывает NPE:
session.setCreationTime(Instant.ofEpochMilli((Long)map.get("creationTime")));
Это ошибка или я упустил что-то новое в Spring Boot 2.0.2+ относительно Spring Session?
UPDATE
Для получения дополнительной информации я создал пример проекта, воспроизводящего проблему: https://github.com/adsanche/test-redis-session
Этот проект содержит простой контроллер, выставляющий две конечные точки:
@Controller
public class HelloController {
@GetMapping(value = "/hello")
public String hello(final WebSession webSession) {
webSession.getAttributes().put("test", "TEST");
return "index";
}
@GetMapping(value = "/invalidate")
public String invalidate(final WebSession webSession) {
webSession.invalidate().subscribe();
return UrlBasedViewResolver.REDIRECT_URL_PREFIX + "/hello";
}
}
Поведение при запуске проекта с Spring Boot 2.0.1
Мы замечаем идентификатор сеанса, начинающийся с 7546ff, и данные сеанса, содержащие атрибут «test» плюс информацию о сеансе по умолчанию (время создания / последнего доступа и т. Д.).
Текущий сеанс признан недействительным, и перенаправление выполняется в «/ hello», где атрибут теста добавляется в новый веб-сеанс.
- Состояние нового сеанса в Redis:
Мы замечаем новый идентификатор сеанса, начинающийся с ba7de, и новые данные сеанса, все еще содержащие атрибут test плюс информацию о сеансе по умолчанию.
Теперь давайте воспроизведем этот сценарий в том же проекте, что и Spring Boot 2.0.3.
Поведение при запуске проекта с Spring Boot 2.0.3
Мы замечаем идентификатор сеанса, начинающийся с 12d61, и данные сеанса, содержащие атрибут «test» плюс информацию о сеансе по умолчанию (время создания / последнего доступа и т. Д.).
Здесь мы заметили, что тот же идентификатор сеанса все еще используется, но сеанс был очищен даже из информации по умолчанию (дата создания и т. Д.). Таким образом, когда он снова вызывается, NPE запускается в репозитории реактивного сеанса redis в методе apply () в месте, которое я упоминал в моем первоначальном сообщении:
Надеюсь, этот пример проекта поможет выяснить, является ли это ошибкой или проблемой реализации на моей стороне.