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 프로젝트이므로 그대로 가져오고 실행하기 쉬워야 합니다.