Developing Triple Communication Services Using Protobuf (IDL)

The Triple protocol supports defining services using Protocol Buffers (Protobuf), making it more user-friendly for those who choose Protobuf for various scenarios such as multi-language, gRPC, and security.

Usage

POM dependency

<plugin>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-maven-plugin</artifactId>
    <version>${dubbo.version}</version> <!-- Version 3.3.0 and above -->
    <configuration>
        <outputDir>build/generated/source/proto/main/java</outputDir> <!-- Refer to the following text for configurable parameters -->
    </configuration>
</plugin>

Configurable parameters

ParameterRequiredDefault valueDescriptionNotes
outputDirfalse${project.build.directory}/generated-sources/protobuf/javaGenerated java file storage directory
protoSourceDirfalse${basedir}/src/main/protoproto file directory
protocArtifactfalsecom.google.protobuf:protoc:3.25.0:exe:Operating System Name:Operating System Architectureproto compiler component
protocVersionfalse3.25.0version of protobuf-java
dubboGenerateTypefalsetriCode generation typeCan be filled with tri or tri_reactor

Service Definition

Define the Greeter service using Protocol Buffers.

syntax = "proto3";
option java_multiple_files = true;
package org.apache.dubbo.samples.tri.unary;

message GreeterRequest {
  string name = 1;
}
message GreeterReply {
  string message = 1;
}

service Greeter{
  rpc greet(GreeterRequest) returns (GreeterReply);
}

Please note the package definition package org.apache.dubbo.samples.tri.unary;. In this example, the path defined in the package will also serve as the Java package name and service prefix. This means the complete definition of the rpc service is: org.apache.dubbo.samples.tri.unary.Greeter, which matches the path of the generated code exactly.

However, keeping consistency is not mandatory; you can define the Java package name separately from the service prefix, which is useful in some cross-language calling scenarios. For instance, in the following IDL definition:

  • The complete service name is greet.Greeter, which will be used during rpc calls and service discovery.
  • The Java package name is defined as org.apache.dubbo.samples.tri.unary, where the generated Java code will be placed.
package greet;
option java_package = "org.apache.dubbo.samples.tri.unary;"
option go_package = "github.com/apache/dubbo-go-samples/helloworld/proto;greet";

Service Implementation

Running mvn clean compile will generate the Dubbo stub code. Next, extend the generated base class DubboGreeterTriple.GreeterImplBase and add specific business logic implementation:

public class GreeterImpl extends DubboGreeterTriple.GreeterImplBase {
    @Override
    public GreeterReply greet(GreeterRequest request) {
        LOGGER.info("Server {} received greet request {}", serverName, request);
        return GreeterReply.newBuilder()
                .setMessage("hello," + request.getName())
                .build();
    }
}

Register the service to the server, where the protocol is set to tri to indicate that the Triple protocol is to be enabled.

public class TriUnaryServer {
    public static void main(String[] args) throws IOException {
        ServiceConfig<Greeter> service = new ServiceConfig<>();
        service.setInterface(Greeter.class);
        service.setRef(new GreeterImpl());

        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
        bootstrap.protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50052))
                .service(service)
                .start().await();
    }
}

Write Client Logic

public class TriUnaryClient {
    public static void main(String[] args) throws IOException {
        DubboBootstrap bootstrap = DubboBootstrap.getInstance();
        ReferenceConfig<Greeter> ref = new ReferenceConfig<>();
        ref.setInterface(Greeter.class);
        ref.setUrl("tri://localhost:50052");

        bootstrap.reference(ref).start();
        Greeter greeter = ref.get();
		final GreeterReply reply = greeter.greet(GreeterRequest.newBuilder().setName("name").build());
    }
}

Frequently Asked Questions

Protobuf Class Not Found

Since the underlying Triple protocol depends on the protobuf protocol for transmission, even if the defined service interface does not use protobuf, the protobuf dependency must still be included in the environment.

<dependency>
	<groupId>com.google.protobuf</groupId>
	<artifactId>protobuf-java</artifactId>
	<version>3.19.4</version>
</dependency>

Additionally, to support direct access to application/json format requests, the following dependency needs to be added.

<dependency>
	<groupId>com.google.protobuf</groupId>
	<artifactId>protobuf-java-util</artifactId>
	<version>3.19.4</version>
</dependency>

Generated Code Cannot Compile

When using Protobuf, ensure that the core Dubbo library version matches the protoc plugin version and run mvn clean compile to regenerate the code.

Before version 3.3.0

Versions before 3.3.0 use protobuf-maven-plugin to configure the protoc plugin, and the dubbo-compiler must match the core dubbo version used:

<plugin>
	<groupId>org.xolstice.maven.plugins</groupId>
	<artifactId>protobuf-maven-plugin</artifactId>
	<version>0.6.1</version>
	<configuration>
		<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
		<outputDirectory>build/generated/source/proto/main/java</outputDirectory>
		<protocPlugins>
			<protocPlugin>
				<id>dubbo</id>
				<groupId>org.apache.dubbo</groupId>
				<artifactId>dubbo-compiler</artifactId>
				<version>${dubbo.version}</version>
				<mainClass>org.apache.dubbo.gen.tri.Dubbo3TripleGenerator</mainClass>
			</protocPlugin>
		</protocPlugins>
	</configuration>
	<executions>
		<execution>
			<goals>
				<goal>compile</goal>
			</goals>
		</execution>
	</executions>
</plugin>

Run the Example

This example demonstrates how to define a service using Protocol Buffers and publish it as an externally callable Triple protocol service. If you have multi-language interoperability, gRPC interaction, or are familiar with and prefer Protobuf development, you can use this approach; otherwise, consider the previous Java interface-based triple development model.

You can view the full code for this example.

First, download the example source code with the following command:

git clone --depth=1 https://github.com/apache/dubbo-samples.git

Change to the example source code directory:

cd dubbo-samples/1-basic/dubbo-samples-api-idl

Compile the project to generate code from the IDL, which calls the protoc plugin provided by Dubbo to generate the corresponding service definition code:

mvn clean compile

The generated code is as follows:

├── build
│   └── generated
│       └── source
│           └── proto
│               └── main
│                   └── java
│                       └── org
│                           └── apache
│                               └── dubbo
│                                   └── samples
│                                       └── tri
│                                           └── unary
│                                               ├── DubboGreeterTriple.java
│                                               ├── Greeter.java
│                                               ├── GreeterOuterClass.java
│                                               ├── GreeterReply.java
│                                               ├── GreeterReplyOrBuilder.java
│                                               ├── GreeterRequest.java
│                                               └── GreeterRequestOrBuilder.java

Start Server

Run the following command to start the server.

mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.unary.TriUnaryServer"

Access the Service

There are two ways to access the Triple service:

  • Using standard HTTP tools
  • Using Dubbo client SDK

cURL Access

curl \
    --header "Content-Type: application/json" \
    --data '{"name":"Dubbo"}' \
    http://localhost:50052/org.apache.dubbo.samples.tri.unary.Greeter/greet/

Dubbo Client Access

Run the following command to start the Dubbo client and complete the service call.

mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.unary.TriUnaryClient"
Last modified October 11, 2024: Update idl usage document (#3041) (e2c3c45727)