Краткое описание как подключить Google Protocol Buffers / Proto3 к вашему Spring проекту
Spring Boot: позволяет быстро разрабатывать stand-alone веб приложения которые вы можете «просто» запустить с минимумом настроек.
Google proto3: легкий, гибкий, автоматический механизм сериализации данных.
Эта статья объяснит как быстро соединить эти технологии вместе. Ознакомиться с технологиями вы можете самостоятельно пройдя по ссылкам в материалах.
Для того чтобы создать новый spring-boot проект вы можете воспользоваться Spring Initializr веб сайтом.
Я выбрал Web как dependency, проект генерировал для maven.
Настройка модуля моделей
В модуле моделей будут находится только файлы с расширением *.proto и автоматически сгенерированные java классы. Proto* файлы помещаются в src/main/proto.
Для примера я создал health.proto:
package demo.domain;
option java_package = "demo.domain";
option java_outer_classname = "HealthCheckProtos";
message HealthCheck {
required string response = 1;
required string timestamp = 2;
required string version = 3;
}
На основании которого будет генериться java класс HealthCheckProtos который я буду использовать в Spring контроллере.
Необходимая конфигурация pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>demo</groupId>
<artifactId>spring-boot-proto3</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-proto3-domain</artifactId>
<packaging>jar</packaging>
<name>spring-boot-proto3-domain</name>
<description>Domain module</description>
<properties>
<protobuf.input.directory>${project.basedir}/src/main/proto</protobuf.input.directory>
<protobuf.output.directory>${project.build.directory}/generated-sources</protobuf.output.directory>
</properties>
<dependencies>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
</dependency>
<dependency>
<groupId>com.googlecode.protobuf-java-format</groupId>
<artifactId>protobuf-java-format</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- copy protoc binary into build directory -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-protoc</id>
<phase>generate-sources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.google.protobuf</groupId>
<artifactId>protoc</artifactId>
<version>${protobuf.version}</version>
<classifier>windows-x86_64</classifier>
<type>exe</type>
<overWrite>true</overWrite>
<outputDirectory>${project.build.directory}</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<!-- compile proto buffer files using copied protoc binary -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>exec-protoc</id>
<phase>generate-sources</phase>
<configuration>
<target>
<property name="protoc.filename" value="protoc-${protobuf.version}-windows-x86_64.exe"/>
<property name="protoc.filepath" value="${project.build.directory}/${protoc.filename}"/>
<chmod file="${protoc.filepath}" perm="ugo+rx"/>
<mkdir dir="${protobuf.output.directory}" />
<path id="protobuf.input.filepaths.path">
<fileset dir="${protobuf.input.directory}">
<include name="**/*.proto"/>
</fileset>
</path>
<pathconvert pathsep=" " property="protobuf.input.filepaths" refid="protobuf.input.filepaths.path"/>
<exec executable="${protoc.filepath}" failonerror="true">
<arg value="-I"/>
<arg value="${protobuf.input.directory}"/>
<arg value="--java_out"/>
<arg value="${protobuf.output.directory}"/>
<arg line="${protobuf.input.filepaths}"/>
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>add-classes</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<$ource>${protobuf.output.directory}</$ource>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Здесь впринципе все стандартно, кроме: classifier у protoc и protoc.filename у maven-antrun-plugin, они к сожалению привязаны к системе на машине сборки, я собирал на Win X64.
Настройка веб модуля
К молулю подключаются spring boot и доменный модуль с классами proto3:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>demo</groupId>
<artifactId>spring-boot-proto3</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-proto3-web</artifactId>
<packaging>jar</packaging>
<name>spring-boot-proto3-web</name>
<description>Web module</description>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>demo</groupId>
<artifactId>spring-boot-proto3-domain</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
После этого необходимо добавить ProtobufHttpMessageConverter к HttpMessageConverter.
package demo.config;
import java.util.HashMap;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
/**
* {@inheritDoc}
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(protobufHttpMessageConverter());
}
/**
* {@inheritDoc}
*/
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.replaceMediaTypes(new HashMap<>()) //
.favorPathExtension(false) //
.defaultContentType(ProtobufHttpMessageConverter.PROTOBUF);
}
@Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
}
Для примера я создал контроллер который бы показывал статус приложения с использованием модели сгенерированной при помощи proto3:
package demo.web;
import java.time.LocalDateTime;
import demo.domain.HealthCheckProtos;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HealthCheckController {
@Value("${health.controller.response}")
private String response;
@Value("${health.controller.version}")
private String version;
@RequestMapping("/ping")
public HealthCheckProtos.HealthCheck get() {
return HealthCheckProtos.HealthCheck.newBuilder() //
.setResponse(response) //
.setTimestamp(LocalDateTime.now().toString()) //
.setVersion(version) //
.build();
}
}
При генерации классов proto3 так же генерирует билдеры которые вы можете использовать для создания модели.
Пример запроса к контроллеру
" alt=«image»/>
Так же добавив header «Accept»:«application/json» вы можете получить тот же ответ сериализованный в json.
Использовался следующий материал:
Исходный код проекта можно скачать тут: bitbucket.org/wickiup/spring-boot-proto3
Быстрый старт со spring boot: projects.spring.io/spring-boot
Быстрый старт с proto3: developers.google.com/protocol-buffers/docs/javatutorial
Поделиться с друзьями