2016-01-03 28 views
6

我在从缓存中获取价值时面临问题。spring-boot-devtools在从缓存中获取时导致ClassCastException。

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弹簧-memcached的3.5.0

价值越来越缓存但获取应用程序时抛出类抛出错误。什么是可能的问题。

Full stack trace

+2

你在类路径上有两次相同的'class'吗?或者你是否已经从多个类加载器(或WebApp环境中的示例)加载它。一个类的通常原因不能被转换为它自己的问题是,类是从不同的地方加载... –

+1

在猜测,它看起来像某种类加载器问题。看起来你有两个不同的加载了相同类的类加载器。 – sisyphus

+0

@sisyphus我使用spring boot + devtools。我读了一些devtools在哪里为静态jar保留一个类加载器,以及一个用于应用程序代码。这会引起问题吗? – titogeo

回答

7

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

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

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

那么我得到了同样的错误,但缓存不是原因。其实我正在使用缓存,但评论缓存没有帮助。

基于这里和那里的提示,我只是介绍了附加的序列化/派生我的对象。这绝对是最好的方式(性能问题),但它的工作。

所以,只是换了别人我改变了我的代码:

@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; 
} 

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

相关问题