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.
protobuf+triple
model but includes service discovery configuration.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
Run the following command to start the server.
mvn compile exec:java -Dexec.mainClass="org.apache.dubbo.samples.tri.unary.TriUnaryServer"
There are two ways to access the Triple service:
curl \
--header "Content-Type: application/json" \
--data '{"name":"Dubbo"}' \
http://localhost:50052/org.apache.dubbo.samples.tri.unary.Greeter/greet/
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"
Due to the use of the IDL development model, the dependencies such as dubbo, protobuf-java must be added. Additionally, plugins like protobuf-maven-plugin must be configured to generate the stub code.
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.19.6</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.19.6</version>
</dependency>
<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>
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:
greet.Greeter
, which will be used during rpc calls and service discovery.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";
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();
}
}
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());
}
}
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>
When using Protobuf, ensure that the core Dubbo library version matches the protoc plugin version and run mvn clean compile
to regenerate the code.
1. After version 3.3.0
Starting from version 3.3.0+, configure the protoc plugin using dubbo-maven-plugin
. The version of dubbo-maven-plugin
must match the core dubbo version used:
<plugin>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-maven-plugin</artifactId>
<version>${dubbo.version}</version>
<configuration>
</configuration>
</plugin>
2. 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>