Получать события сеанса из репозитория сеансов Hazelcast?

#spring #session #events #hazelcast

Вопрос:

Я не получаю события закрытия сеанса или истечения срока действия при использовании встроенного репозитория сеансов Hazelcast в приложении Spring boot. Я действительно получаю события создания сеанса. У меня очень короткий тайм-аут для сеансов (30 секунд). Я проверил, что срок действия сеанса истекает через 30 секунд, получив «несанкционированный» ответ с сервера. Как вы получаете события истечения/уничтожения сеанса?

Это моя конфигурация сеанса:

 @Configuration
@EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = 30)
public class SessionConfiguration{

    @Bean
    @SpringSessionHazelcastInstance
    public HazelcastInstance hazelcastInstance() {
        Config config = new Config();
        config.setClusterName("spring-session-cluster");

        // Add this attribute to be able to query sessions by their PRINCIPAL_NAME_ATTRIBUTE's
        AttributeConfig attributeConfig = new AttributeConfig()
                .setName(Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
                .setExtractorClassName(Hazelcast4PrincipalNameExtractor.class.getName());

        // Configure the sessions map
        config.getMapConfig(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME)
                .addAttributeConfig(attributeConfig).addIndexConfig(
                new IndexConfig(IndexType.HASH, Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE));

        // Use use custom serializer to de/serialize sessions faster. This is optional.
        SerializerConfig serializerConfig = new SerializerConfig();
        serializerConfig.setImplementation(new HazelcastSessionSerializer()).setTypeClass(MapSession.class);
        config.getSerializationConfig().addSerializerConfig(serializerConfig);

        return Hazelcast.newHazelcastInstance(config);
    }
    
    @Bean
    public SessionRepositoryCustomizer<Hazelcast4IndexedSessionRepository> customize() {
        return (sessionRepository) -> {
            sessionRepository.setFlushMode(FlushMode.IMMEDIATE);
            sessionRepository.setSaveMode(SaveMode.ALWAYS);
            sessionRepository.setSessionMapName(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME);
            sessionRepository.setDefaultMaxInactiveInterval(30); //this is extra; tried with and without
        };
    }
}
 

И это мой слушатель:

 @Component
public class SessionListener {
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SessionListener.class);

    @EventListener
    public void sessionCreated(SessionCreatedEvent event) {
        log.info("SESSION:CREATE:ID=" event.getSessionId()); //only this gets called but none of the others
    }
    
    @EventListener
    public void sessionDeleted(SessionDeletedEvent event) {
        log.info("SESSION:DELETE:ID=" event.getSessionId());
    }
    
    @EventListener
    public void sessionDestroyed(SessionDestroyedEvent event) {
        log.info("SESSION:DESTROY:ID=" event.getId());
    }
    
    @EventListener
    public void sessionExpired(SessionExpiredEvent event) {
        log.info("SESSION:EXPIRE:ID=" event.getSessionId());
    }
}
 

Ответ №1:

Частичный ответ (я точно не знаю, почему это работает):

Если вы добавите прослушиватель карты сеанса в HazelcastInstance (в компоненте создания), вы внезапно начнете получать события Sessionexpired.

Поэтому замените строки:

 config.getMapConfig(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME)
            .addAttributeConfig(attributeConfig).addIndexConfig(
            new IndexConfig(IndexType.HASH, Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE));
 

с (установите максимальное количество секунд простоя в конфигурации карты сеанса):

 config.getMapConfig(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME)
            .addAttributeConfig(attributeConfig).addIndexConfig(
            new IndexConfig(IndexType.HASH, Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE))
            .setMaxIdleSeconds(tout);
 

и

 return Hazelcast.newHazelcastInstance(config);
 

с помощью (добавить прослушиватель записи сеанса на карту сеанса)

 HazelcastInstance instance = Hazelcast.newHazelcastInstance(config);
IMap<Object, Object> map = instance.getMap( Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME );
map.addEntryListener( new HazelcastSessionEntryListener(), true );
return instance;
 

где HazelcastSessionEntryListener может быть определен следующим образом:

 @Component
public class HazelcastSessionEntryListener implements EntryListener<Object, Object>
{
    public HazelcastSessionEntryListener(){}

    @Override
    public void entryAdded(EntryEvent<Object, Object> event){}

    @Override
    public void entryUpdated(EntryEvent<Object, Object> event){}

    @Override
    public void entryRemoved(EntryEvent<Object, Object> event){}

    @Override
    public void entryEvicted(EntryEvent<Object, Object> event){}

    @Override
    public void entryExpired(EntryEvent<Object, Object> event){}

    @Override
    public void mapCleared(MapEvent event){}

    @Override
    public void mapEvicted(MapEvent event){}
}
 

Забавно, что HazelcastSessionEntryListener в моем случае-это просто пустая реализация (она ничего не делает). Похоже на поведение с ошибками (но я не эксперт по весне).