2016-01-03 53 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只是類的提示。

相關問題