1. 개요

이 기사에서는 언어에 구애받지 않는 잘 알려진 바이너리 데이터 형식인 Google 프로토콜 버퍼 (protobuf) 를 살펴보겠습니다 . 프로토콜을 사용하여 파일을 정의할 수 있으며 다음으로 해당 프로토콜을 사용하여 Java, C++, C#, Go 또는 Python과 같은 언어로 코드를 생성할 수 있습니다.

이것은 형식 자체에 대한 소개 기사입니다. Spring 웹 애플리케이션에서 형식을 사용하는 방법을 알고 싶다면 이 기사 를 참조하십시오 .

2. Maven 의존성 정의

프로토콜 버퍼를 사용하려면 protobuf-java 에 Maven 의존성을 추가해야 합니다 .

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>${protobuf.version}</version>
</dependency>

<properties>
    <protobuf.version>3.2.0</protobuf.version>
</properties>

3. 프로토콜 정의

예를 들어 시작하겠습니다. protobuf 형식으로 매우 간단한 프로토콜을 정의할 수 있습니다.

message Person {
    required string name = 1;
}

이것은 하나의 필수 필드( 문자열 유형 이 있는 이름)만 있는 Person 유형의 단순 메시지 프로토콜입니다 .

프로토콜을 정의하는 더 복잡한 예를 살펴보겠습니다. 사람 세부 정보를 protobuf 형식으로 저장해야 한다고 가정해 보겠습니다.

패키지 프로토버프;

package protobuf;

option java_package = "com.baeldung.protobuf";
option java_outer_classname = "AddressBookProtos";

message Person {
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;

    repeated string numbers = 4;
}

message AddressBook {
    repeated Person people = 1;
}

우리의 프로토콜은 사람주소록의 두 가지 유형의 데이터로 구성됩니다. 코드를 생성한 후(나중 섹션에서 자세히 설명) 해당 클래스는 AddressBookProtos 클래스 내부의 내부 클래스가 됩니다.

필수 필드를 정의하려는 경우(즉, 해당 필드 없이 객체를 생성하면 예외 가 발생한다는 의미) 필수 키워드 를 사용해야 합니다.

선택적 키워드 로 필드를 생성하면 이 필드를 설정할 필요가 없습니다. 반복되는 키워드 는 가변 크기의 배열 유형입니다.

모든 필드가 인덱싱됩니다. 숫자 1로 표시된 필드는 이진 파일의 첫 번째 필드로 저장됩니다. 2로 표시된 필드는 다음에 저장됩니다. 그러면 메모리에 필드가 배치되는 방식을 더 잘 제어할 수 있습니다.

4. Protobuf 파일에서 자바 코드 생성하기

파일을 정의하면 파일에서 코드를 생성할 수 있습니다.

먼저 머신에 protobuf를 설치 해야 합니다. 이렇게 하면 protoc 명령을 실행하여 코드를 생성할 수 있습니다.

protoc -I=. --java_out=. addressbook.proto

protoc 명령 은 addressbook.proto 파일 에서 Java 출력 파일을 생성 합니다 . -I 옵션은 proto 파일이 있는 디렉토리를 지정 합니다 . java-out생성된 클래스가 생성될 디렉토리를 지정합니다.

생성된 클래스에는 정의된 메시지에 대한 설정자, 게터, 생성자 및 빌더가 있습니다. 또한 protobuf 파일을 저장하고 바이너리 형식에서 Java 클래스로 역직렬화하기 위한 몇 가지 util 메서드가 있습니다.

5. Protobuf 정의 메시지 인스턴스 생성

생성된 코드를 사용하여 Person 클래스의 Java 인스턴스를 쉽게 만들 수 있습니다.

String email = "j@baeldung.com";
int id = new Random().nextInt();
String name = "Michael Program";
String number = "01234567890";
AddressBookProtos.Person person =
  AddressBookProtos.Person.newBuilder()
    .setId(id)
    .setName(name)
    .setEmail(email)
    .addNumbers(number)
    .build();

assertEquals(person.getEmail(), email);
assertEquals(person.getId(), id);
assertEquals(person.getName(), name);
assertEquals(person.getNumbers(0), number);

원하는 메시지 유형에 대해 newBuilder() 메서드 를 사용하여 유창한 빌더를 만들 수 있습니다 . 모든 필수 필드를 설정한 후에는 build() 메서드를 호출하여 Person 클래스 의 인스턴스를 만들 수 있습니다 .

6. Protobuf 직렬화 및 역직렬화

Person 클래스 의 인스턴스를 생성 하면 생성된 프로토콜과 호환되는 이진 형식으로 디스크에 저장하려고 합니다. AddressBook 클래스의 인스턴스를 만들고 해당 개체에 한 사람을 추가 한다고 가정해 보겠습니다 .

다음으로 해당 파일을 디스크에 저장하고 싶습니다 . 자동 생성 코드에 다음과 같이 사용할 수 있는 writeTo() util 메서드가 있습니다.

AddressBookProtos.AddressBook addressBook 
  = AddressBookProtos.AddressBook.newBuilder().addPeople(person).build();
FileOutputStream fos = new FileOutputStream(filePath);
addressBook.writeTo(fos);

이 메서드를 실행한 후 개체는 바이너리 형식으로 직렬화되어 디스크에 저장됩니다. 디스크에서 해당 데이터를 로드하고 다시 AddressBook 개체 로 역직렬화하려면 mergeFrom() 메서드를 사용할 수 있습니다.

AddressBookProtos.AddressBook deserialized
  = AddressBookProtos.AddressBook.newBuilder()
    .mergeFrom(new FileInputStream(filePath)).build();
 
assertEquals(deserialized.getPeople(0).getEmail(), email);
assertEquals(deserialized.getPeople(0).getId(), id);
assertEquals(deserialized.getPeople(0).getName(), name);
assertEquals(deserialized.getPeople(0).getNumbers(0), number);

7. 결론

이 빠른 기사에서는 데이터를 이진 형식으로 설명하고 저장하기 위한 표준인 Google 프로토콜 버퍼를 소개했습니다.

우리는 간단한 프로토콜을 만들고 정의된 프로토콜을 준수하는 Java 인스턴스를 만들었습니다. 다음으로 protobuf를 사용하여 객체를 직렬화 및 역직렬화하는 방법을 살펴보았습니다.

이 모든 예제와 코드 스니펫의 구현은 GitHub 프로젝트 에서 찾을 수 있습니다. 이것은 Maven 프로젝트이므로 그대로 가져오고 실행하기 쉬워야 합니다.

Generic footer banner