Проект управления сессиями нового поколения Spring Session

Spring Boot Redis Spring HTTP

Приветствую всех вОблако Tencent + сообщество, получить больше крупной технической практики Tencent по галантерее ~

Эта статья взята изОблако + Сообщество Бюро переводов,Зависит отTnecesocкомпилировать.

Управление сеансами всегда было важной частью корпоративных приложений Java. Но долгое время эта часть считалась решенной проблемой, и серьезных нововведений не было.

Однако современная тенденция к микросервисам и горизонтально масштабируемым облачным приложениям обнажает некоторые недостатки в дизайне современной технологии управления сеансами, ставя под сомнение некоторые выводы, которые мы сделали об этом дизайне за последние 20 с лишним лет.

В этой статье будет продемонстрирован подход, который использует Spring Session API, чтобы помочь нам преодолеть некоторые ограничения предыдущего подхода к управлению сеансом. Сначала мы обобщим проблемы с текущими технологиями управления сеансами, а затем углубимся в стратегии, которые использует Spring Session для их решения. Наконец, мы подытожим, как работает Spring Session и некоторые варианты использования в конкретных проектах.

Spring Session революционизирует управление сеансами для корпоративных Java-приложений, позволяя нам легко:

  • Написание масштабируемого облачного приложения
  • Поместите сохраненное состояние сеанса в специальном внешнем хранилище сеанса, такими как Redis или Apache Geode, который обеспечивает высококачественный кластер хранения с одним сервером приложений.
  • Держите HttpSession в сети, пока пользователь делает запрос через WebSocket
  • Доступ к данным сеанса из инструкций по обработке не-веб-запросов, таких как инструкции по обработке сообщений JMS.
  • Обеспечивает поддержку создания нескольких сеансов для каждого браузера для более удобного взаимодействия с конечным пользователем.
  • Управляйте обменом идентификаторами сеансов между клиентом и сервером, тем самым создавая RESTul API, которые извлекают идентификаторы сеансов в заголовках HTTP-сообщений, не полагаясь на файлы cookie.

Обратите внимание, что проект Spring Session на самом деле не зависит от Spring Framework, поэтому мы можем использовать его даже в проектах, которые не используют Spring Framework.

Проблемы с традиционными методами управления сессиями

Целью Spring Session является решение различных проблем традиционной технологии управления сеансами JavaEE. Вот несколько примеров, иллюстрирующих некоторые из этих вопросов.

Создавайте горизонтально масштабируемые облачные приложения

С точки зрения архитектуры облачных приложений приложение должно иметь возможность горизонтального масштабирования за счет развертывания большего количества экземпляров путем запуска большего количества контейнеров Linux в большом пуле виртуальных машин. Например, мы можем легко развернуть военный файл такого приложения в Tomcat на Cloud Foundry или Heroku и за секунды масштабировать до 100 экземпляров приложения, каждый с 1 ГБ ОЗУ. Мы также можем настроить облачную платформу на автоматическое увеличение или уменьшение количества экземпляров приложений в зависимости от требований пользователя.

Многие приложения сохраняют состояние сеанса HTTP в JVM, на которой выполняется код приложения. Это легко реализовать, и доступ быстрый. Когда экземпляр приложения присоединяется к кластеру или покидает его, хранилище сеансов HTTP равномерно перераспределяется между всеми оставшимися экземплярами приложения. В гибкой облачной среде мы запускаем сотни экземпляров приложений, и количество экземпляров может быстро увеличиваться или уменьшаться в любое время. Это вызывает некоторые вопросы:

  • Перераспределение хранилища сеансов HTTP может стать узким местом производительности;
  • Пространство кучи, необходимое для хранения большого количества сеансов, слишком велико, что приводит к частому выполнению процесса сборки мусора и снижению производительности;
  • Многоадресная рассылка TCP обычно запрещена облачной инфраструктурой, но часто используется диспетчерами сеансов для обнаружения экземпляров приложений, присоединяющихся к кластеру или покидающих его.

Следовательно, более эффективно хранить состояние сеанса HTTP в хранилище данных за пределами JVM-кода приложения. Например, redis можно установить и использовать для хранения состояния сеанса в вышеупомянутых 100 случаях Tomcat, то увеличение или уменьшение количества экземпляров Tomcat не повлияет на режим хранения сеанса в Redis. Кроме того, поскольку redis написан в C, он может использовать сотни гигабайт или даже терабайт памяти без мусора, влияющего на его операцию.

Для сервера с открытым исходным кодом, такого как Tomcat, легко найти другие реализации методов управления сеансами, которые используют внешние хранилища данных, такие как Redis или Memcached, но используемый процесс настройки может быть сложным, а процесс настройки для каждого сервера приложений может быть сложным. не то же самое. Для продуктов с закрытым исходным кодом, таких как WebSphere и Weblogic, часто невозможно найти подходящие альтернативные реализации методов управления сеансами.

Spring Session предоставляет независимый от сервера приложений метод для настройки хранилища данных подключаемого сеанса, что позволяет нам реализовать такое хранилище в рамках сервлета, не полагаясь на API сервера приложений. Это означает, что Spring Session может работать со всеми серверами приложений, реализующими спецификацию Servlet (Tomcat, Jetty, WebSphere, WebLogic, JBoss), и настраивается одинаково и просто на всех серверах приложений.

Мы также можем выбрать наиболее подходящее внешнее хранилище данных сеанса в соответствии с нашими потребностями. Это делает Spring Session платформой, которая может помочь нам перенести традиционные приложения JavaEE в облако и служитьДвенадцать факторовидеальный инструмент миграции.

один пользователь, несколько аккаунтов

Предположим, вы запускаете общедоступные веб-приложения на сайте example.com, и какой-то пользователь создает несколько учетных записей. Например, у пользователя может быть две учетные записи Jeff Lebowski thedude@example.com и lebowski@example.com. Подобно другим веб-приложениям Java, которые можно использовать для отслеживания различных состояний сеанса HttpSession, таких как текущий вход пользователя. Поэтому, когда пользователь хочет переключиться с dude@example.com на lebowski@example.com, необходимо выйти из текущей учетной записи и войти снова.

Использование Spring Session для настройки нескольких сеансов HTTP для каждого пользователя очень просто. В этот момент Джефф Лебовски может переключаться между thedude@example.com и lebowski@example.com, не выходя из системы и не входя в нее.

Предварительный просмотр на разных уровнях безопасности

Представьте, что вы хотите создать веб-приложение со сложной настраиваемой системой авторизации, в которой пользователи с разными разрешениями будут иметь разные стили пользовательского интерфейса приложения.

Например, предположим, что приложение имеет четыре уровня безопасности: общедоступный, конфиденциальный, секретный и совершенно секретный. Когда пользователь входит в приложение, система распознает уровень безопасности этого пользователя и отображает данные только до его уровня безопасности включительно. Таким образом, пользователи с общедоступным уровнем могут видеть документы с общедоступным уровнем, пользователи с секретным уровнем могут видеть общедоступный и секретный уровни и так далее. Чтобы сделать пользовательский интерфейс более удобным для пользователя, наше приложение также должно позволять пользователю предварительно просматривать, как будет выглядеть пользовательский интерфейс приложения при более низких уровнях безопасности. Например, сверхсекретные пользователи должны иметь возможность предварительно просматривать внешний вид различных вещей в приложении в секретном режиме.

Типичное веб-приложение будет хранить идентификатор текущего пользователя и его уровень безопасности или роль в сеансе HTTP. Однако, поскольку у каждого пользователя веб-приложения есть только один сеанс, роль пользователя можно переключить, только выйдя из системы и снова войдя в нее, или реализовав несколько сеансов для одного пользователя.

С Spring Session мы можем легко создать независимый сеанс, реализовать несколько функций для предварительного просмотра каждого пользователя, вошедшего в систему, будет так просто. Например, когда текущий пользователь вошел в приложения сверхсекретного уровня с предварительным уровнем конфиденциальности, который вы хотите, вы можете создать и использовать новый уровень безопасности в качестве конфиденциального разговора.

Оставайтесь в системе при использовании веб-сокетов

Представьте себе другой сценарий, в котором, когда пользователь входит в наше веб-приложение через example.com, он может вести беседу, используя клиент живого чата HTML5, который работает через веб-сокеты. Однако, согласно спецификации сервлета, запросы, сделанные через веб-сокеты, не обновляют время истечения сеанса, поэтому, пока пользователь общается в чате, независимо от того, как часто он общается, сеанс может быть потерян, а затем соединение с веб-сокетом будет потеряно. В результате он будет закрыт, и чат не сможет продолжаться.

Опять же, с помощью Spring Session мы можем легко гарантировать, что как запросы Websocket, так и обычные HTTP-запросы могут обновлять время истечения срока действия сеанса.

Доступ к данным сеанса для не-веб-запросов

Представьте еще раз, что наше приложение предоставляет два метода доступа: один — RESTful API через HTTP, а другой — сообщения AMQP через RabbitMQ. В этот момент поток, выполняющий сообщение AMQP, не может получить доступ к серверу приложений.HttpSessionДа, нам нужно написать собственное решение для доступа к данным в сеансе HTTP.

По-прежнему с Spring Session, если мы знаем идентификатор сеанса, мы можем получить доступ к Spring Session из любого потока в приложении. Spring Session имеет более богатый API, чем предыдущий диспетчер сеансов Servlet HTTP, поэтому нам нужно знать только идентификатор сеанса, чтобы найти сеанс, который мы ищем. Например, мы можем использовать поле идентификатора пользователя входящего сообщения, чтобы напрямую найти соответствующий сеанс.

Как работает весенняя сессия

Теперь, когда ограничения традиционных серверов приложений в управлении сеансами HTTP были продемонстрированы в различных контекстах, давайте посмотрим, как Spring Session решает эти проблемы.

Архитектура весенней сессии

При реализации диспетчера сеансов необходимо решить две ключевые проблемы:

  • Как создать эффективный, надежный и высокодоступный кластер хранения данных сеанса?
  • Как я могу определить, какой экземпляр сеанса может быть связан с каким входящим запросом (в виде HTTP, WebSocket, AMQP и т. д.)?

Но по сути, есть более критический вопрос: как передавать идентификатор сеанса в разных протоколах запроса?

Первая проблема хорошо решается для Spring Session различными высокодоступными и масштабируемыми кластерными хранилищами (Redis, Gemfire, Apache Geode и др.). Поэтому Spring Session также должен определить набор стандартных интерфейсов, чтобы обеспечить доступ к базовому хранилищу данных с использованием различных хранилищ данных. Весенняя сессия определяетSessionа такжеExpiringSessionВ дополнение к этим основным ключевым интерфейсам также определены ключевые интерфейсы для доступа к различным хранилищам данных.SessionRepository.

  • org.springframework.session.SessionИнтерфейс, определяющий основные функции сеанса, такие как установка и удаление свойств. Этот интерфейс не зависит от конкретной базовой технологии, поэтому его можно сравнить с интерфейсом в Servlet.HttpSessionПрименимо к большему количеству ситуаций;
  • org.springframework.session.ExpiringSessionОн расширяет интерфейс сеанса. Он предоставляет свойства, которые позволяют нам устанавливать чувствительный ко времени сеанс и запрашивать, истек ли срок действия сеанса.RedisSessionЭто пример реализации этого интерфейса.
  • org.springframework.session.SessionRepositoryОпределяет методы создания, сохранения, удаления и поиска сеансов. Фактическая логика сохранения сеанса в хранилище данных прописана в конкретной реализации этого интерфейса. НапримерRedisOperationsSessionRepositoryЭто реализация этого интерфейса, которая использует Redis для создания, сохранения и удаления сеансов.

Что касается вопроса связывания запроса с конкретным экземпляром сеанса, Spring Session предполагает, что процесс этого связывания специфичен для протокола, поскольку клиент и сервер должны согласовать передаваемый идентификатор сеанса в течение цикла запрос/ответ. Например, если клиент отправляет запрос HTTP, сеанс может быть связан с запросом через заголовок Cookie или HTTP. Если сделан запрос HTTPS, сеанс можно связать с запросом, используя поле идентификатора сеанса SSL. Если это входящее сообщение JMS, заголовок сообщения также может использоваться для хранения идентификатора сеанса между запросом и ответом.

Для связанных операций протокола HTTP сеанс Spring определяетHttpSessionStrategyИнтерфейс, последний имеет печенье и сеансы вместеCookieHttpSessionStrategyИ используйте первое поле пользовательских пакетов для управления сессиями.HeaderHttpSessionStrategyДве реализации.

Давайте подробнее рассмотрим, как Spring Session работает по протоколу HTTP.

На момент публикации этой статьи (10.11.2015) Spring Session 1.0.2 в текущем общедоступном выпуске предоставляет набор реализаций Spring Session с использованием Redis, а также реализацию, поддерживающую любую распределенную карту (например, Hazelcast). На самом деле реализовать поддержку Spring Session для определенного хранилища данных относительно просто, и таких реализаций в сообществе с открытым исходным кодом уже много.

Весенняя сессия через HTTP

Spring Session over HTTP реализован как стандартный фильтр сервлетов. Этот фильтр должен перехватывать все запросы к веб-приложению и должен быть первым в цепочке фильтров. Фильтры Spring Session отвечают за то, чтобы весь последующий кодjavax.servlet.http.HttpServletRequest.getSession()Вызовы методов представлены в сеансе Spinrg.HttpSessionэкземпляр вместо стандартного, предоставленного сервером приложенийHttpSession.

Самый простой способ понять это — взглянуть на фактический исходный код Spring Session. Мы начнем со стандартных точек расширения сервлета, используемых для реализации Spring Session.

В 2001 году в спецификации Servlet 2.3 был представлен ServletRequestWrapper. такого родаJavadocНазванный ServletRequestWrapper «предоставляет удобную реализацию интерфейса ServletRequest, которая позволяет разработчикам наследовать от него, чтобы адаптироваться к конкретному сервлету. Этот класс принимает шаблон оболочки или декоратора. Определены методы класса ServletRequest этого класса. быть передан объекту запроса, который он инкапсулирует." Следующий код, извлеченный из Tomcat, показывает, как реализован ServletRequestWrapper.

public class ServletRequestWrapper implements ServletRequest {

    private ServletRequest request;

    /**
     * Creates a ServletRequest adaptor wrapping the given request object. 
     * 创建一个装有给定的请求对象的 ServletRequest 适配器
     * @throws java.lang.IllegalArgumentException if the request is null
     * 如果请求对象为空就会抛出空指针异常
     */
    public ServletRequestWrapper(ServletRequest request) {
        if (request == null) {
            throw new IllegalArgumentException("Request cannot be null");   
        }
        this.request = request;
    }

    public ServletRequest getRequest() {
        return this.request;
    }
    
    public Object getAttribute(String name) {
        return this.request.getAttribute(name);
    }

    // 为可读性着想, 接下来的代码就略了
}

Спецификация Servlt 2.3 также исправляетServletRequestWrapperопределяет подклассHttpServletRequestWrapper. Мы можем использовать его для быстрой реализации пользовательскогоHttpServletRequest. Следующий код, извлеченный из Tomcat, показываетHttpServletRequestWrapperКак реализован этот класс.

public class HttpServletRequestWrapper extends ServletRequestWrapper 
    implements HttpServletRequest {

    public HttpServletRequestWrapper(HttpServletRequest request) {
	    super(request);
    }
    
    private HttpServletRequest _getHttpServletRequest() {
 	   return (HttpServletRequest) super.getRequest();
    }
  
    public HttpSession getSession(boolean create) {
     return this._getHttpServletRequest().getSession(create);
    }
   
    public HttpSession getSession() {
      return this._getHttpServletRequest().getSession();
    }
    
    // 为可读性着想,接下来的代码就略了  
}

Следовательно, мы можем использовать эти классы-оболочки для написания некоторого кода, расширяющего функциональность HttpServletRequest, и перегружать метод, возвращающий HttpSession, чтобы последний возвращал сеанс, который мы сохранили во внешнем репозитории. Вот исходный код из проекта Spring Session, который соответствует упомянутым здесь вещам. Чтобы соответствовать объяснению здесь, исходные комментарии в исходном коде были переписаны мной, так что я мог бы также взглянуть на комментарии внутри.

/*
 * Spring Session 项目定义了一个继承了标准 HttpServletRequestWrapper 的类
 * 它重载了 HttpServletRequest 里面的所有跟会话有关的方法
 */
private final class SessionRepositoryRequestWrapper
   extends HttpServletRequestWrapper {

   private HttpSessionWrapper currentSession;
   private Boolean requestedSessionIdValid;
   private boolean requestedSessionInvalidated;
   private final HttpServletResponse response;
   private final ServletContext servletContext;

   /*
   * 构造方法这块非常简单
   * 它会接收并设置一些之后会用到的参数,
   * 然后完成对 HttpServletRequestWrapper 的代理
   */
   private SessionRepositoryRequestWrapper(
      HttpServletRequest request,
      HttpServletResponse response,
      ServletContext servletContext) {
     super(request);
     this.response = response;
     this.servletContext = servletContext;
   }

   /*
   * Spring Session 便在这里用自己对返回存储于外部数据源的会话数据的实现
   * 取代了对应用服务器提供的默认方法的代理调用.
   * 
   * 这里的实现会先检查它是不是已经有一个对应的会话. 
   * 若有那就返回之, 否则就会检查当前的请求附带的会话 ID 是否确实对应着一个会话
   * 若有, 那就用这个会话 ID 从 SessionRepository 里边加载这个会话;
   * 若外部数据源里没这个会话, 或者这个会话 ID 没对应的会话,
   * 那就创建一个新的会话, 并把它存在会话数据存储里面.
   */
   @Override
   public HttpSession getSession(boolean create) {
     if(currentSession != null) {
       return currentSession;
     }
     String requestedSessionId = getRequestedSessionId();
     if(requestedSessionId != null) {
       S session = sessionRepository.getSession(requestedSessionId);
       if(session != null) {
         this.requestedSessionIdValid = true;
         currentSession = new HttpSessionWrapper(session, getServletContext());
         currentSession.setNew(false);
         return currentSession;
       }
     }
     if(!create) {
       return null;
     }
     S session = sessionRepository.createSession();
     currentSession = new HttpSessionWrapper(session, getServletContext());
     return currentSession;
   }

   @Override
   public HttpSession getSession() {
     return getSession(true);
   }
}

Spring Session также определяетServletFilterКласс реализации интерфейсаSessionRepositoryFilter. Исходный код основной части реализации этого фильтра также будет приведен здесь, а также будут приложены некоторые комментарии, соответствующие содержанию этой статьи, так что вы можете взглянуть.

/*
 * SessionRepositoryFilter 是一个标准 ServletFilter 的实现.
 * 其目的是从它的基类扩展出一些功能来.
 */
public class SessionRepositoryFilter < S extends ExpiringSession >
    extends OncePerRequestFilter {

	/*
	 * 这一方法就是核心部分.
	 * 该方法会创建一个我们在上面介绍过的包装请求的实例,
	 * 然后拿这个包装过的请求再过一遍过滤器链的剩余部分.
	 * 关键的地方在于,应用在执行位于这个过滤器之后的代码时,
	 * 如果要获取会话的数据, 那这个包装过的请求就会返回 Spring Session
	 * 所保存在外部数据源的 HttpServletSession 实例.
	 */
	protected void doFilterInternal(
	    HttpServletRequest request,
	    HttpServletResponse response,
	    FilterChain filterChain) throws ServletException, IOException {

		request.setAttribute(SESSION_REPOSITORY_ATTR, sessionRepository);

		SessionRepositoryRequestWrapper wrappedRequest =
		  new SessionRepositoryRequestWrapper(request,response,servletContext);

		SessionRepositoryResponseWrapper wrappedResponse =
		  new SessionRepositoryResponseWrapper(wrappedRequest, response);

		HttpServletRequest strategyRequest =
		     httpSessionStrategy.wrapRequest(wrappedRequest, wrappedResponse);

		HttpServletResponse strategyResponse =
		     httpSessionStrategy.wrapResponse(wrappedRequest, wrappedResponse);

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

Смысл этого раздела в том, что Spring Session over HTTP на самом деле является просто классическим фильтром сервлета, который использует стандартные функции спецификации сервлета для реализации функциональности. Следовательно, должна быть возможность изменить военный файл существующего веб-приложения для использования Spring Session без изменения существующего кода. Однако в приложении используетсяjavax.servlet.http.HttpSessionListenerявляется исключением. Spring Session 1.0 неHttpSessionListenerПоддержка предоставляется, но она была добавлена ​​в выпуске Spring Session 1.1 M1.Подробнее см. здесь.

Настройки весенней сессии

В веб-проекте настройка Spring Session разделена на четыре этапа:

  • Настройте хранилище данных, используемое в Spring Session.
  • Добавьте файл Spring Session .jar в веб-приложение.
  • Добавьте фильтры Spring Session в конфигурацию веб-приложения.
  • Настройте подключение из Spring Session к выбранному хранилищу данных сеанса.

Spring Session имеет встроенную поддержку Redis. Подробности установки и настройки Redisпосмотреть здесь.

Существует два распространенных способа выполнить описанные выше действия по настройке Spring Session. Один из них — использовать Spring Boot для автоматической настройки Spring Session. Другой — вручную завершить каждый шаг настройки.

Инструменты управления зависимостями, такие как Maven и Gradle, упрощают добавление Spring Session в зависимости вашего приложения. Например, если вы используете Spring Boot + Maven, вы можете добавить в pom.xml следующие зависимости:

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session</artifactId>
    <version>1.0.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-redis</artifactId>
</dependency>

spring-boot-starter-redisЭта зависимость гарантирует, что jar-файлы, необходимые для взаимодействия с Redis, будут включены в приложение, поэтому Spring Boot можно использовать для автоматической настройки. Что касаетсяspring-sessionЭтот проект зависимостей соответствует пакету jar Spring Session.

Процесс настройки фильтра Spring Session Servlet может выполняться Spring Boot автоматически, просто добавьте его в класс конфигурации Spring Boot.@EnableRedisHttpSessionПросто аннотируйте. Так же, как следующий код:

@SpringBootApplication
@EnableRedisHttpSession
public class ExampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(ExampleApplication.class, args);
    }
}

Добавьте следующую информацию о конфигурации в файл application.properties Spring Boot, чтобы настроить соединение между Spring Session и Redis.

spring.redis.host=localhost
spring.redis.password=secret
spring.redis.port=6379

Чтобы настроить соединение с Redis, Spring Boot предоставляет подробную базовую архитектуру, которая позволяет нам произвольно настроить способ установления соединения с Redis. Вы можете найти пошаговые инструкции в Spring Session и Spring Boot.гид.

Учебник по настройке традиционного веб-приложения для использования Spring Session с помощью web.xmlпосмотреть здесь.

Учебник по настройке традиционного файла войны без web.xml для использования Spring Sessionпосмотреть здесь.

По умолчанию Spring Session использует файлы cookie HTTP для хранения идентификаторов сеанса, но мы также можем настроить Spring Session на использование настраиваемых полей заголовка HTTP (например,x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3

) для хранения идентификатора сеанса, который может быть очень полезен при создании RESTful API. полное руководствопосмотреть здесь.

Использование весенней сессии

После настройки Spring Session мы можем использовать стандартный API Servlet для взаимодействия с ним. Например, следующий код определяет сервлет, который использует стандартный API сеанса сервлета для доступа к данным сеанса.

@WebServlet("/example")
public class Example extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    // 使用标准的 servlet API 去获取对应的会话数据
    // 这一会话数据就是 Spring Session 存在 Redis
    // 或是别的我们所指定的数据源里面的会话数据

    HttpSession session = request.getSession();
    String value = session.getAttribute(“someAttribute”);

  }
}

Один браузер, несколько сеансов

Spring Session делает это с помощью_sПараметр идентификатора сеанса для отслеживания нескольких сеансов для каждого пользователя. Если URL-адрес входящего запросаhttp://example.com/doSomething?_s=0, то Spring Session будет читать_sЗначение параметра, и тогда будет считаться, что этот запрос соответствует сеансу по умолчанию.

Если URL-адрес входящего запросаhttp://example.com/doSomething?_s=1, тогда Spring Session будет знать, что кодовое имя сеанса, соответствующего этому запросу, равно 1. Если во входящем запросе не указаны параметры_s, тогда Spring Session будет рассматривать его как соответствующий диалог по умолчанию (т.е._s = 0).

Чтобы каждый браузер создавал новую сессию, мы просто вызываем, как и раньшеjavax.servlet.http.HttpServletRequest.getSession(), то Spring Session вернет соответствующий сеанс или создаст новый сеанс, используя семантику спецификации сервлета. В таблице ниже приведеныgetSession()Конкретное выражение метода для разных параметров URL одного и того же браузера:

URL-адрес HTTP-запроса код сеанса Конкретная производительность getSession()
example.com/resource 0 Возвращает сеанс, связанный с кодом 0, если он существует, в противном случае создает новый сеанс и связывает его с кодом 0.
example.com/resource?_s=1 1 Возвращает сеанс, связанный с кодовым именем 1, если он существует, в противном случае создает новый сеанс и связывает его с кодовым именем 1.
example.com/resource?_s=0 0 Возвращает сеанс, связанный с кодом 0, если он существует, в противном случае создает новый сеанс и связывает его с кодом 0.
example.com/resource?_s=abc abc Возвращает сеанс, связанный с кодовым именем abc, если он существует, в противном случае создает новый сеанс и связывает его с кодовым именем abc.

Как показано в таблице выше, идентификаторы сеансов не ограничены целыми числами, если они отличаются от всех других псевдонимов сеансов, опубликованных для пользователя, их можно использовать для нового сеанса. Однако кодовое имя сеанса целочисленного типа должно быть самым простым в использовании, и Spring Session также даетHttpSessionManagerчтобы предоставить некоторые служебные методы для обработки идентификаторов сеансов.

мы можем пройти"org.springframework.session.web.HttpSessionManager"Это имя свойства, чтобы найти соответствующее свойство, а затем доступ кHttpSessionManager. Следующий код демонстрирует, как получитьHttpSessionManagerМетоды, на которые ссылаются, а также некоторые из основных методов этого класса служебных методов.

@WebServlet("/example")
public class Example extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest request,HttpServletResponse response)
  throws ServletException, IOException {

    /*
     * 通过使用 "org.springframework.session.web.http.HttpSessionManager"
     * 这一属性名在请求属性中查找属性
     * 来获取一个 Spring Session 的 HttpSessionManager 的引用
     */

    HttpSessionManager sessionManager=(HttpSessionManager)request.getAttribute(
        "org.springframework.session.web.http.HttpSessionManager");

    /*
     * 用 HttpSessionManager 来找出 HTTP 请求所对应的会话代号.
     * 默认情况下这个会话代号会由 HTTP 请求的 URL 参数 _s 给出。
     * 比如 http://localhost:8080/example?_s=1 这个 URL
     * 就会让这里的 println() 方法打印 "Requested Session Alias is: 1"
     */
    String requestedSessionAlias=sessionManager.getCurrentSessionAlias(request);
    System.out.println("Requested Session Alias is:  " + requestedSessionAlias);

    /* 
     * 返回一个当前还没被浏览器用在请求参数里的唯一的会话代号.
     * 注意这一方法并不会创建一个新的会话, 
     * 创建新的会话还是要通过 request.getSession() 来进行.
     */
    String newSessionAlias = sessionManager.getNewSessionAlias(request);

    /* 
     * 使用刚刚得到的新会话代号构造一个 URL,
     * 使其含有 _s 这个参数.
     * 比如若 newSessionAlias 的值是 2,
     * 那么这个方法就会返回 "/inbox?_s=3" 
     */
    String encodedURL = sessionManager.encodeURL("/inbox", newSessionAlias);
    System.out.println(encodedURL);

    /* 
     * 返回一个会话代号为键, 会话 ID 为值的 Map, 
     * 以便识别浏览器发来的请求所对应的会话.
     */
    Map <String, String> sessionIds = sessionManager.getSessionIds(request);
  }
}

В заключение

Spring Session революционизирует управление сеансами для корпоративных Java-приложений, позволяя нам легко:

  • Написание горизонтально масштабируемых облачных приложений
  • Сохранение состояния сеанса вне системы в выделенном внешнем хранилище сеансов, таком как Redis или Apache Geode, которое обеспечивает высококачественные кластеры хранения независимым от сервера приложений способом.
  • Держите HttpSession в сети, пока пользователь делает запрос через WebSocket
  • Доступ к данным сеанса из инструкций по обработке не-веб-запросов, таких как инструкции по обработке сообщений JMS.
  • Обеспечивает поддержку создания нескольких сеансов для каждого браузера для более удобного взаимодействия с конечным пользователем.
  • Управляйте обменом идентификаторами сеансов между клиентом и сервером, тем самым создавая RESTul API, которые извлекают идентификаторы сеансов в заголовках HTTP-сообщений, не полагаясь на файлы cookie.

Если вы ищете способ освободиться от традиционных и громоздких серверов приложений, но ограничены возможностями кластеризации хранилища сеансов сервера приложений, облегчение Spring Session таких контейнеров, как Tomcat, Jetty и Undertow, будет хорошим выбором.

использованная литература

Проект весенней сессии

Учебники и руководства по весенней сессии

Взаимодействие тайм-аута Websocket/HttpSession

Интернет-конференция:Введение в весеннюю сессию


вопросы и ответы

Как аутентификация, авторизация и управление сеансами реализованы в традиционных веб-приложениях и API?

Связанное Чтение

Проектирование архитектуры Spring Session Управление сеансами распределенного кластера

Анализ исходного кода класса ключа Spring Session

Фреймворк с открытым исходным кодом, который может превратить веб-формы в диалоговые формы.


Эта статья была разрешена автором для публикации сообщества Tencent Cloud +, исходная ссылка: https://cloud.tencent.com/developer/article/1151972?fromSource=waitui.

Приветствую всех вОблако Tencent + сообществоИли обратите внимание на общедоступную учетную запись WeChat сообщества Yunjia (QcloudCommunity) и как можно скорее получите больше массовой технической практики галантерейных товаров ~