1. 概述
本文将介绍 JaVers 库的核心功能。这个库专门用于检测和追踪 Java 对象的状态变更。当我们在代码中使用可变对象时,对象可能在应用的多个位置被修改——JaVers 能帮我们精准捕获并审计这些变更,简直是调试和审计的利器。
2. Maven 依赖配置
先在 pom.xml
中添加核心依赖:
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-core</artifactId>
<version>3.1.0</version>
</dependency>
最新版本请查阅 Maven 中央仓库。
3. 检测 POJO 状态变更
以简单的 Person
类为例:
public class Person {
private Integer id;
private String name;
// 标准 getter/constructor
}
假设在应用某处创建了 Person
对象,而另一处修改了相同 id 对象的 name 字段。我们需要对比这两个对象,找出具体变更点。
使用 JaVers 的 compare()
方法轻松搞定:
@Test
public void givenPersonObject_whenApplyModificationOnIt_thenShouldDetectChange() {
// given
Javers javers = JaversBuilder.javers().build();
Person person = new Person(1, "Michael Program");
Person personAfterModification = new Person(1, "Michael Java");
// when
Diff diff = javers.compare(person, personAfterModification);
// then
ValueChange change = diff.getChangesByType(ValueChange.class).get(0);
assertThat(diff.getChanges()).hasSize(1);
assertThat(change.getPropertyName()).isEqualTo("name");
assertThat(change.getLeft()).isEqualTo("Michael Program");
assertThat(change.getRight()).isEqualTo("Michael Java");
}
4. 检测对象列表状态变更
处理对象集合时,同样需要逐个检测元素状态变更。常见场景包括:
- 从列表中移除对象
- 向列表中新增对象
- 修改列表中对象的属性
看个实际例子:当从列表中移除某个对象时,这种变更可能引发问题,我们需要审计整个列表的变化。用 compareCollections()
方法实现:
@Test
public void givenListOfPersons_whenCompare_ThenShouldDetectChanges() {
// given
Javers javers = JaversBuilder.javers().build();
Person personThatWillBeRemoved = new Person(2, "Thomas Link");
List<Person> oldList =
Lists.asList(new Person(1, "Michael Program"), personThatWillBeRemoved);
List<Person> newList =
Lists.asList(new Person(1, "Michael Not Program"));
// when
Diff diff = javers.compareCollections(oldList, newList, Person.class);
// then
assertThat(diff.getChanges()).hasSize(3);
ValueChange valueChange =
diff.getChangesByType(ValueChange.class).get(0);
assertThat(valueChange.getPropertyName()).isEqualTo("name");
assertThat(valueChange.getLeft()).isEqualTo("Michael Program");
assertThat(valueChange.getRight()).isEqualTo("Michael Not Program");
ObjectRemoved objectRemoved = diff.getChangesByType(ObjectRemoved.class).get(0);
assertThat(
objectRemoved.getAffectedObject().get().equals(personThatWillBeRemoved))
.isTrue();
ListChange listChange = diff.getChangesByType(ListChange.class).get(0);
assertThat(listChange.getValueRemovedChanges().size()).isEqualTo(1);
}
5. 对比对象图结构
实际项目中常遇到对象图(对象嵌套对象)。假设有 PersonWithAddress
类包含 Address
列表,当给人员新增地址时:
@Test
public void givenListOfPerson_whenPersonHasNewAddress_thenDetectThatChange() {
// given
Javers javers = JaversBuilder.javers().build();
PersonWithAddress person =
new PersonWithAddress(1, "Tom", Arrays.asList(new Address("England")));
PersonWithAddress personWithNewAddress =
new PersonWithAddress(1, "Tom",
Arrays.asList(new Address("England"), new Address("USA")));
// when
Diff diff = javers.compare(person, personWithNewAddress);
List objectsByChangeType = diff.getObjectsByChangeType(NewObject.class);
// then
assertThat(objectsByChangeType).hasSize(1);
assertThat(objectsByChangeType.get(0).equals(new Address("USA")));
}
删除地址同样会被检测到:
@Test
public void givenListOfPerson_whenPersonRemovedAddress_thenDetectThatChange() {
// given
Javers javers = JaversBuilder.javers().build();
PersonWithAddress person =
new PersonWithAddress(1, "Tom", Arrays.asList(new Address("England")));
PersonWithAddress personWithNewAddress =
new PersonWithAddress(1, "Tom", Collections.emptyList());
// when
Diff diff = javers.compare(person, personWithNewAddress);
List objectsByChangeType = diff.getObjectsByChangeType(ObjectRemoved.class);
// then
assertThat(objectsByChangeType).hasSize(1);
assertThat(objectsByChangeType.get(0).equals(new Address("England")));
}
6. 总结
JaVers 是个实用的变更检测库,核心优势包括:
✅ 简单 POJO 变更检测:基础属性修改一目了然
✅ 集合变更追踪:列表增删改全面覆盖
✅ 对象图深度对比:复杂嵌套结构也能轻松搞定
对于需要审计对象状态变更的场景(如配置管理、数据同步),这个库简直是“简单粗暴”的解决方案。完整代码示例请访问 GitHub。