Spring 的 Infinispan,从缓存投射失败

Infinispan with Spring, casting from cache failing

我有 Spring 1.4 应用程序部署到 WildFly 10,它使用 WildFly 内置的 Infinispan 8.1。

我已经成功部署了应用程序,这是 Infinispan 的配置: 1) 缓存管理器

@Bean
public CacheManager cacheManager() throws Exception {
    JndiTemplate jndiTemplate = new JndiTemplate();
    EmbeddedCacheManager embededCacheManager = (EmbeddedCacheManager) jndiTemplate.lookup("java:jboss/infinispan/container/CONTAINER");
    SpringEmbeddedCacheManager cacheManager = new SpringEmbeddedCacheManager(embededCacheManager);
}

2) pom.xml

<dependency>
    <groupId>org.infinispan</groupId>
    <artifactId>infinispan-spring</artifactId>
    <version>8.1.0.Final</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </exclusion>
        <exclusion>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-jcl</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
        <archive>
            <manifestEntries>
                <Dependencies>org.infinispan, org.infinispan.commons, org.jboss.as.clustering.infinispan export</Dependencies>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

当我第一次部署应用程序时,一切正常。但是,在启动缓存后,重新部署应用程序时,我在使用缓存时收到以下错误:

java.lang.ClassCastException: com.dplesa.Class cannot be cast to com.dplesa.Class

我用不同的 类 尝试过,但无论我做什么,错误都是一样的。但是,我没有从缓存简单字符串的缓存中得到这个错误。是什么导致了这个问题?

这听起来很可怕,但在本例中,行为是正确的。

A class 总是绑定到特定的 classloader。 Wildfly 使用模块化 classloader,每个部署使用不同的 classloader 实例。现在假设您使用 classloader 'A' 放置了 class 的一些实例,进行重新部署(classloader 'A' 正在处理并使用加载新部署classloader 'B') 并尝试使用 classloader 'B' 从缓存中读取数据。那些 class 加载器不匹配,这导致您的异常 - Class com.dplesa.Class 无法转换为 com.dplesa.Class.

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

  1. 将 Infinispan 嵌入您的应用程序(例如使用 infinispan-embedded 工件)。有了这个技巧,Infinispan 将加载与您的域 classes.

  2. 相同的 classloader
  3. 将您的域 class 放入 Wildfly 模块中。

  4. 单独部署 Infinispan 集群并使用 HotRod 客户端连接到它(例如使用 infinispan-remote 工件)。

解决方案 #1 是最简单的,但您需要注意在重新部署期间您的集群发生了什么(确保您的节点 join/leave 集群正确,您的数据按您的需要复制等)。