6

我在运行在 Spring Boot 1.4.0M3 上的应用程序中遇到了一个奇怪的问题,该应用程序使用 Spring 缓存实现,其中提供者是 Redis,我收到 classCastException 无法转换相同的对象

我使用 Mongodb 作为数据库,我有用户对象,其中包含延迟加载的角色对象列表,角色内部包含权限对象,如下所示

@Document
@Data
public class User implements Serializable{
private String passwordResetToken;

private boolean enabled = false;

@DBRef(lazy= true)
private List<Role> roleList;
}

我的角色 DTO 如下

@Data
@Document
public class Role implements Serializable{
   private String roleName;
    private String description;
    @DBRef(lazy= true)
    private List<Permission> permissions;
}

现在在我的 Spring MVC 中,在加载所有角色时,我正在调用所有权限,因为这是重复操作,我想到了缓存结果并使用 redis,并在加载角色值时收到以下异常。

raised java.lang.ClassCastException: com.learning.securedapp.domain.Permission cannot be cast to com.learning.securedapp.domain.Permission

帮助我克服这个错误。

我将源代码附加到我的项目中,并且在RoleController.java的第 91 行收到错误

要在本地环境中复制,登录到应用程序并单击权限菜单,然后单击角色菜单,在角色菜单中现在单击任何编辑图标。您将收到上述错误。

4

4 回答 4

9

当您将 DevTools 与缓存一起使用时,您需要注意此限制

当对象被序列化到缓存中时,应用程序类加载器是 C1。然后在您更改一些代码/配置后,devtools 会自动重新启动上下文并创建一个新的类加载器 (C2)。当您点击该缓存方法时,缓存抽象会在缓存中找到一个条目,并将其从存储中反序列化。如果缓存库不考虑上下文类加载器,则该对象将附加错误的类加载器(这解释了那个奇怪的异常A cannot be cast to A)。

TL;DR如果缓存库不使用上下文类加载器,请不要使用 devtools 序列化类。或者将您的缓存库放在应用程序类加载器中

restart.include.yourcache=/my-cache-lib-[\\w-]+\.jar
于 2016-06-23T07:19:32.160 回答
4

这对我有用,DevTools 和 Redis 都在工作。我们需要在创建 JdkSerializationRedisSerializer 时传递 classLoader 并且它应该可以工作

 JdkSerializationRedisSerializer redisSerializer = new JdkSerializationRedisSerializer(getClass().getClassLoader());

所以我的 RedisCacheConfig 是:

@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport implements CachingConfigurer {


............................
............................


    @Bean
public RedisCacheManager redisCacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
    JdkSerializationRedisSerializer redisSerializer = new JdkSerializationRedisSerializer(getClass().getClassLoader());

    RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
            .disableCachingNullValues()
            .entryTtl(Duration.ofHours(redisDataTTL))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer));

    redisCacheConfiguration.usePrefix();

    RedisCacheManager redisCacheManager = RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(lettuceConnectionFactory)
            .cacheDefaults(redisCacheConfiguration)
            .build();

    redisCacheManager.setTransactionAware(true);
    return redisCacheManager;
}

............................
............................


}

检查这个春季启动问题:https ://github.com/spring-projects/spring-boot/issues/9444

于 2020-08-14T09:32:09.830 回答
3

我使用的是 Spring Boot 2.0.5,我最终从 pom.xml 中完全删除了 devtools。感谢@Always Learning 的上述回答。
尽管我讨厌这样做,但我现在找不到其他方法!

  <!-- 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
     -->    
于 2018-10-27T00:56:51.633 回答
3

我实际上尝试了建议的解决方案(及其许多变体),但没有运气。例如,这并没有阻止问题的发生:

restart.include.cache=/spring-data-redis-.*.jar

我更新了上面的内容以标注我正在使用的特定版本,但它仍然无法正常工作。

我最终所做的工作是将spring-boot-devtools从我的项目中排除。我正在使用 Maven,所以注释是这样的:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <version>[1.5.9,)</version>
        <scope>provided</scope>
    </dependency>

这将阻止加载任何等于或大于 1.5.9 的版本。在我包含上述内容后,一切都按预期工作。我知道这对所有人来说都不是一个理想的解决方案,但是我很少使用 devtools 的重启功能,所以这对我来说实际上是一个好方法。

于 2018-03-07T21:43:24.620 回答