数据库对象持久化后反序列化无法转换为源 Class: ClassCastException: TestDomain 无法转换为 TestDomain

Deserialized after persistence in Database object can't be casted into source Class: ClassCastException: TestDomain cannot be cast to TestDomain

我在 spring-session 中遇到了以下问题:

@RestController
public class TestService {

    @Autowired
    private SessionRepository sessionRepository;

    @GetMapping("/test")
    public void test() {
        Session session = sessionRepository.createSession();
        TestDomain testDomain = new TestDomain("a", 1);
        session.setAttribute(session.getId(), testDomain);
        sessionRepository.save(session);

        Session session1 = sessionRepository.getSession(session.getId());
        Object testDomainObj = session1.getAttribute(session1.getId());
        // I wonder why TestDomainObj is not an instance of TestDomain??
        System.out.println("Does testDomainObj from session represent the instance of TestDomain class: " + (testDomainObj instanceof TestDomain));

        // java.lang.ClassCastException: com.example.demo.TestDomain cannot be cast to com.example.demo.TestDomain
        TestDomain testDomain1 = (TestDomain) testDomainObj;
        System.out.println(testDomain1);
    }
}

我试着搜索了一下,得到testDomainObj后发现是​​Objectclass的实例。因此,很明显反序列化的对象丢失了它的元信息。

我这样配置 JdbcOperationsSessionRepository

@Configuration
public class AppConfig {
    @Bean
    SessionRepository sessionFactoryBean(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
        return new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
    }
}

并在 application.properties 中激活它:

spring.session.store-type=jdbc
spring.session.jdbc.initializer.enabled=true

最后一件事 testDomain 对象在执行 sessionRepository.save(session);

后已保存在数据库中

如何理解和应对这个问题?

好吧,我回答我的问题。在我的例子中,我应该像这样为反序列化器指定 ClassLoader:

@Bean
SessionRepository sessionFactoryBean(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
    JdbcOperationsSessionRepository sessionRepository = new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
    GenericConversionService conversionService = new GenericConversionService();
    conversionService.addConverter(Object.class, byte[].class,
            new SerializingConverter());
    conversionService.addConverter(byte[].class, Object.class,
            new DeserializingConverter(Thread.currentThread().getContextClassLoader()));
    sessionRepository.setConversionService(conversionService);
    return sessionRepository;
}

您遇到此问题是因为您手动注册了 JdbcOperationsSessionRepository bean,而不是重复使用 Spring 会话 JDBC 配置工具,即 @EnableJdbcHttpSession。参见 the relevant code in JdbcHttpSessionConfiguration

Spring Boot 通过为 Spring Session 提供 auto-configuration 支持使这变得更加容易,因此您甚至不需要使用 @EnableJdbcHttpSession。只需将 spring.session.store-type=jdbc 添加到配置属性即可为您处理一切。