【问题标题】:spring-boot-devtools causing ClassCastException while getting from cache.spring-boot-devtools 在从缓存中获取时导致 ClassCastException。
【发布时间】:2016-04-07 06:51:21
【问题描述】:

我在从缓存中获取价值时遇到问题。

java.lang.RuntimeException: java.lang.ClassCastException: com.mycom.admin.domain.User cannot be cast to com.mycom.admin.domain.User

缓存配置

@Configuration
@EnableCaching
@AutoConfigureAfter(value = { MetricsConfiguration.class, DatabaseConfiguration.class })
@Profile("!" + Constants.SPRING_PROFILE_FAST)
public class MemcachedCacheConfiguration extends CachingConfigurerSupport {

    private final Logger log = LoggerFactory.getLogger(MemcachedCacheConfiguration.class);

    @Override
    @Bean
    public CacheManager cacheManager() {
        ExtendedSSMCacheManager cacheManager = new ExtendedSSMCacheManager();
        try {
            List<SSMCache> list = new ArrayList<>();
            list.add(new SSMCache(defaultCache("apiCache"), 86400, false));
            cacheManager.setCaches(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cacheManager;
    }


    @Override
    public CacheResolver cacheResolver() {
        return null;
    }

    @Override
    public CacheErrorHandler errorHandler() {
        return null;
    }

    private Cache defaultCache(String cacheName) throws Exception {
        CacheFactory cacheFactory = new CacheFactory();
        cacheFactory.setCacheName(cacheName);
        cacheFactory.setCacheClientFactory(new MemcacheClientFactoryImpl());
        String serverHost = "127.0.0.1:11211";
        cacheFactory.setAddressProvider(new DefaultAddressProvider(serverHost));
        cacheFactory.setConfiguration(cacheConfiguration());
        return cacheFactory.getObject();
    }

    @Bean
    public CacheConfiguration cacheConfiguration() {
        CacheConfiguration cacheConfiguration = new CacheConfiguration();
        cacheConfiguration.setConsistentHashing(true);
        return cacheConfiguration;
    }

}

并带有注释

@Cacheable(value = "apiCache#86400", key = "'User-'.concat(#login)")

我正在使用 com.google.code.simple-spring-memcached 3.5.0

值正在被缓存,但在获取应用程序时抛出类转换错误。可能的问题是什么。

Full stack trace

【问题讨论】:

  • 你的类路径中有两次相同的class 吗?或者您是否从多个类加载器(或 WebApp 环境中的示例)加载它。无法将类转换为自身问题的通常原因是类是从不同的地方加载的......
  • 猜测,它看起来像是某种 ClassLoader 问题。看起来你有两个不同的类加载器,它们加载了同一个类。
  • @sisyphus 我使用 spring boot + devtools。我读过一些 devtools 为静态 jars 保留一个类加载器和一个用于应用程序代码的地方。这会导致问题吗?
  • @BoristheSpider 是的,我删除了 spring-boot-devtools 及其工作。谢谢各位
  • 我应该提出有关 spring-boot 的问题吗?根据他们的指导方针,他们正在观看此标签。另外我不认为这是可以解决的,请提出建议。

标签: java spring-boot memcached jhipster spring-cache


【解决方案1】:

这是a known limitation of Devtools。当缓存条目被反序列化时,对象没有附加到正确的类加载器。

有多种方法可以解决此问题:

  1. 在开发中运行应用程序时禁用缓存
  2. 使用不同的缓存管理器(如果您使用 Spring Boot 1.3,您可以使用 application-dev.properties 中的 spring.cache.type 属性强制使用 simple 缓存管理器,并在您的 IDE 中启用开发配置文件)
  3. 将 memcached(以及缓存的内容)配置为 run in the application classloader。我不推荐这个选项,因为上面的前两个更容易实现

【讨论】:

    【解决方案2】:

    好吧,我得到了同样的错误,但缓存不是原因。实际上我正在使用缓存,但是将缓存注释掉并没有帮助。

    根据这里和那里的提示,我刚刚介绍了我的对象的附加序列化/反序列化。这绝对是最好的方法(性能问题),但它确实有效。

    所以,我只是为其他人更改了我的代码:

    @Cacheable("tests")
    public MyDTO loadData(String testID) {
        // add file extension to match XML file
        return (MyDTO) this.xmlMarshaller.loadXML(String.format("%s/%s.xml", xmlPath, testID));
    }
    

    到:

    @Cacheable("tests")
    public MyDTO loadData(String testID) {
        // add file extension to match XML file
        Object dtoObject = this.xmlMarshaller.loadXML(String.format("%s/%s.xml", xmlPath, testID));
        byte[] data = serializeDTO(dtoObject);
        MyDTO dto = deserializeDTO(data);
        return dto;
    }
    
    private MyDTO deserializeDTO(byte[] data) {
        MyDTO dto = null;
        try {
            ByteArrayInputStream fileIn = new ByteArrayInputStream(data);
            ObjectInputStream in = new ConfigurableObjectInputStream(fileIn,
                    Thread.currentThread().getContextClassLoader());
            dto = (MyDTO) in.readObject();
            in.close();
            fileIn.close();
        } catch (Exception e) {
            String msg = "Deserialization of marshalled XML failed!";
            LOG.error(msg, e);
            throw new RuntimeException(msg, e);
        }
        return dto;
    }
    
    private byte[] serializeDTO(Object dtoObject) {
        byte[] result = null;
        try {
            ByteArrayOutputStream data = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(data);
            out.writeObject(dtoObject);
            out.close();
            result = data.toByteArray();
            data.close();
        } catch (IOException e) {
            String msg = "Serialization of marshalled XML failed!";
            LOG.error(msg, e);
            throw new RuntimeException(msg, e);
        }
    
        return result;
    }
    

    注意:这不是任何复杂的解决方案,而只是使用 ConfigurableObjectInputStream 类的提示。

    【讨论】:

      【解决方案3】:

      在启用 STS 插件的 eclipse 中运行项目时,我遇到了同样的问题。即使我从项目中完全删除了 devtools 依赖项。它仍然在eclipse中启用。为了解决这个问题,我不得不禁用 devtools。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-04-25
        • 2021-10-10
        • 2020-10-24
        • 2016-10-31
        • 2021-01-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多