Hazelcast 简明教程

Hazelcast - Serialization

Hazelcast 最好用于数据/查询分布在多台机器的环境中。在这些环境中,数据需要从我们的 Java 对象序列化为能够在网络上传输的字节数组。

Hazelcast 支持多种序列化类型。但是,让我们关注一些常用类型,即 Java 序列化和 Java Externalizable。

Java Serialization

Example

首先让我们了解一下 Java 序列化。假设我们定义了一个实现了 Serializable 接口的 Employee 类。

public class Employee implements Serializable{
   private static final long serialVersionUID = 1L;
   private String name;
   private String department;
   public Employee(String name, String department) {
      super();
      this.name = name;
      this.department = department;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getDepartment() {
      return department;
   }
   public void setDepartment(String department) {
      this.department = department;
   }
   @Override
   public String toString() {
      return "Employee [name=" + name + ", department=" + department + "]";
   }
}

现在让我们编写代码将 Employee 对象添加到 Hazelcast 映射中。

public class EmployeeExample {
   public static void main(String... args){
      //initialize hazelcast server/instance
      HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance();
      //create a set to track employees
      Map<Employee, String> employeeOwners=hazelcast.getMap("employeeVehicleMap");
      Employee emp1 = new Employee("John Smith", "Computer Science");
      // add employee to set
      System.out.println("Serializing key-value and add to map");
      employeeOwners.put(emp1, "Honda");
      // check if emp1 is present in the set
      System.out.println("Serializing key for searching and Deserializing
      value got out of map");
      System.out.println(employeeOwners.get(emp1));
      // perform a graceful shutdown
      hazelcast.shutdown();
   }
}

Output

它将生成如下输出:

Serializing key-value and add to map
Serializing key for searching and Deserializing value got out of map
Honda

在此,一个非常重要的方面是,只需通过实现 Serializable 接口,我们就可以让 Hazelcast 使用 Java 序列化。另外请注意,Hazelcast 会存储键和值序列化的数据,而不是将它们像 HashMap 一样存储在内存中。因此,Hazelcast 负责序列化和反序列化的繁重工作。

Example

但是,这里有一个陷阱。在上述情况下,如果员工的部门发生改变怎么办?这个人仍然是同一个人。

public class EmployeeExampleFailing {
   public static void main(String... args){
      //initialize hazelcast server/instance
      HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance();
      //create a set to track employees
      Map<Employee, String> employeeOwners=hazelcast.getMap("employeeVehicleMap");
      Employee emp1 = new Employee("John Smith", "Computer Science");
      // add employee to map
      System.out.println("Serializing key-value and add to map");
      employeeOwners.put(emp1, "Honda");
      Employee empDeptChange = new Employee("John Smith", "Electronics");
      // check if emp1 is present in the set
      System.out.println("Checking if employee with John Smith is present");
      System.out.println(employeeOwners.containsKey(empDeptChange));
      Employee empSameDept = new Employee("John Smith", "Computer Science");
      System.out.println("Checking if employee with John Smith is present");
      System.out.println(employeeOwners.containsKey(empSameDept));
      // perform a graceful shutdown
      hazelcast.shutdown();
   }
}

Output

它将生成如下输出:

Serializing key-value and add to map
Checking if employee with name John Smith is present
false
Checking if employee with name John Smith is present
true

这是因为 Hazelcast 在比较时并不会对键(即 Employee)进行反序列化。它直接比较序列化键的字节码。因此,所有属性的值都相同的对象会被视为相同对象。但如果这些属性的值发生了改变,例如上述场景中的部门,则这两个键会被视为唯一键。

Java Externalizable

如果在上述示例中,我们在对键进行序列化/反序列化时不关心部门的值怎么办。Hazelcast 也支持 Java Externalizable,它让我们可以控制用于序列化和反序列化的标签。

Example

让我们修改我们的 Employee 类 −

public class EmplyoeeExternalizable implements Externalizable {
   private static final long serialVersionUID = 1L;
   private String name;
   private String department;
   public EmplyoeeExternalizable(String name, String department) {
      super();
      this.name = name;
      this.department = department;
   }
   @Override
   public void readExternal(ObjectInput in) throws IOException,
   ClassNotFoundException {
      System.out.println("Deserializaing....");
      this.name = in.readUTF();
   }
   @Override
   public void writeExternal(ObjectOutput out) throws IOException {
      System.out.println("Serializing....");
      out.writeUTF(name);
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getDepartment() {
      return department;
   }
   public void setDepartment(String department) {
      this.department = department;
   }
   @Override
   public String toString() {
      return "Employee [name=" + name + ", department=" + department + "]";
   }
}

因此,正如您从代码中看到的那样,我们添加了 readExternal/writeExternal 方法,它们负责序列化/反序列化。鉴于我们在序列化/反序列化时是对部门不感兴趣的,所以我们在 readExternal/writeExternal 方法中排除了部门。

Example

现在,如果我们执行以下代码 −

public class EmployeeExamplePassing {
   public static void main(String... args){
      //initialize hazelcast server/instance
      HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance();
      //create a set to track employees
      Map<EmplyoeeExternalizable, String> employeeOwners=hazelcast.getMap("employeeVehicleMap");
      EmplyoeeExternalizable emp1 = new EmplyoeeExternalizable("John Smith", "Computer Science");
      // add employee to map
      employeeOwners.put(emp1, "Honda");
      EmplyoeeExternalizable empDeptChange = new EmplyoeeExternalizable("John Smith", "Electronics");
      // check if emp1 is present in the set
      System.out.println("Checking if employee with John Smith is present");
      System.out.println(employeeOwners.containsKey(empDeptChange));
      EmplyoeeExternalizable empSameDept = new EmplyoeeExternalizable("John Smith", "Computer Science");
      System.out.println("Checking if employee with John Smith is present");
      System.out.println(employeeOwners.containsKey(empSameDept));
      // perform a graceful shutdown
      hazelcast.shutdown();
   }
}

Output

我们得到的输出是 −

Serializing....
Checking if employee with John Smith is present
Serializing....
true
Checking if employee with John Smith is present
Serializing....
true

正如输出所示,使用 Externalizable 接口,我们可以仅提供员工姓名的序列化数据给 Hazelcast。

另外请注意,Hazelcast 序列化我们的键两次 −

  1. 一次是在存储键时,

  2. 第二次是在地图中搜索给定键时。如前文所述,这是因为 Hazelcast 使用序列化的字节数组来比较键。

总体而言,与 Serializable 相比,使用 Externalizable 的优势更多,因为如果我们想要更多地控制要序列化的属性以及我们希望如何处理它们,它提供了更多控制权。