【发布时间】:2021-12-09 23:01:35
【问题描述】:
我有一个带有 Spring Boot 2.5.5 和嵌入式 Infinispan 12.1.7 的 Web 应用程序。
我有一个带有端点的控制器,可以通过 ID 获取 Person 对象:
@RestController
public class PersonController {
private final PersonService service;
public PersonController(PersonService service) {
this.service = service;
}
@GetMapping("/person/{id}")
public ResponseEntity<Person> getPerson(@PathVariable("id") String id) {
Person person = this.service.getPerson(id);
return ResponseEntity.ok(person);
}
}
以下是在getPerson 方法上使用@Cacheable 注释的PersonService 实现:
public interface PersonService {
Person getPerson(String id);
}
@Service
public class PersonServiceImpl implements PersonService {
private static final Logger LOG = LoggerFactory.getLogger(PersonServiceImpl.class);
@Override
@Cacheable("person")
public Person getPerson(String id) {
LOG.info("Get Person by ID {}", id);
Person person = new Person();
person.setId(id);
person.setFirstName("John");
person.setLastName("Doe");
person.setAge(35);
person.setGender(Gender.MALE);
person.setExtra("extra value");
return person;
}
}
这是 Person 类:
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String firstName;
private String lastName;
private Integer age;
private Gender gender;
private String extra;
/* Getters / Setters */
...
}
我将 infinispan 配置为使用基于文件系统的缓存存储:
<?xml version="1.0" encoding="UTF-8"?>
<infinispan xmlns="urn:infinispan:config:12.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:12.1 https://infinispan.org/schemas/infinispan-config-12.1.xsd">
<cache-container default-cache="default">
<serialization marshaller="org.infinispan.commons.marshall.JavaSerializationMarshaller">
<allow-list>
<regex>com.example.*</regex>
</allow-list>
</serialization>
<local-cache-configuration name="mirrorFile">
<persistence passivation="false">
<file-store path="${infinispan.disk.store.dir}"
shared="false"
preload="false"
purge="false"
segmented="false">
</file-store>
</persistence>
</local-cache-configuration>
<local-cache name="person" statistics="true" configuration="mirrorFile">
<memory max-count="500"/>
<expiration lifespan="86400000"/>
</local-cache>
</cache-container>
</infinispan>
我请求端点获取 id 为“1”的人:http://localhost:8090/assets-webapp/person/1PersonService.getPerson(String) 第一次被调用,结果被缓存。
我再次请求端点以获取 id 为“1”的人,并在缓存中检索结果。
我通过使用 getter/setter 删除 extra 字段来更新 Person 对象,并添加一个 extra2 字段:
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String firstName;
private String lastName;
private Integer age;
private Gender gender;
private String extra2;
...
public String getExtra2() {
return extra2;
}
public void setExtra2(String extra2) {
this.extra2 = extra2;
}
}
我再次请求端点获取 id 为“1”的人,但抛出了 ClassCastException:
java.lang.ClassCastException: com.example.controller.Person cannot be cast to com.example.controller.Person] with root cause java.lang.ClassCastException: com.example.controller.Person cannot be cast to com.example.controller.Person
at com.example.controller.PersonServiceImpl$$EnhancerBySpringCGLIB$$ec42b86.getPerson(<generated>) ~[classes/:?]
at com.example.controller.PersonController.getPerson(PersonController.java:19) ~[classes/:?]
我通过删除 extra2 字段并添加 extra 字段来回滚 Person 对象修改。
我再次请求端点获取 id 为“1”的人,但总是抛出 ClassCastException
infinispan 使用的编组器是JavaSerializationMarshaller。
如果类已经重新编译,我猜 java 序列化不允许取消缓存数据。
但我想知道如何避免这种情况,尤其是能够在访问缓存数据时管理类的更新(添加/删除字段)而不会出现异常。
有人有解决办法吗?
【问题讨论】:
-
由于类转换异常没有意义(它是同一个类),我推测它是一个类加载器问题。 Spring缓存配置是什么?
-
@cruftex 我刚刚添加了 \@EnableCaching 来启用缓存,我在 PersonServiceImpl.getPerson(String id) 方法上使用了 \@Cacheable。属性:spring.cache.type=infinispan, infinispan.embedded.configXml=config/cache/infinispan.xml
标签: java spring spring-boot caching infinispan