In Quick Start, you have successfully run the basic example of tRPC-Java
, but
that is just the beginning. In this tutorial, you will continue to learn:
- The way to define
tRPC-Java
services by Protocol Buffer. - The way to configure
tRPC-Java
services by YAML file. - The way to integrate
tRPC-Java
with Spring Boot. - The extension capabilities that
tRPC-Java
have. - Various features supported by
tRPC-Java
.
To achieve cross-language compatibility, tRPC
relies on the Protocol Buffer v3 (referred to
as protobuf
in the following tutorial) for its services definition. You can refer to
its Official Documents for more information.
tRPC-Java
already provides the minimum service dependency. Before starting to customize your
service, you can include the following dependency:
<dependency>
<groupId>com.tencent.trpc</groupId>
<artifactId>trpc-mini</artifactId>
<version>${tRPC-Java.version}</version>
</dependency>
The example codes in the
tRPC-Java
repository already include the above dependency, you can skip this section and proceed with the following tutorial if you are going to run the example codes in thetRPC-Java
repository.
To define a new service, you need to declare it in protobuf
first. The following example defines a
service named GreeterService
:
service GreeterService {
// ...
}
In a service, there can be multiple methods defined within the service body. The following example
demonstrates the definition of a method called sayHello
for the service GreeterService
. This
method takes HelloRequest
as its parameter and returns HelloResponse
.
service GreeterService {
rpc sayHello (HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
// ...
}
message HelloResponse {
// ...
}
A detailed tRPC
services definition in protobuf
can be found
at trpc-java-demo/src/main/proto/demo.proto
.
Indeed, protobuf
provides a language-independent service definition. You can use
the trpc-maven-plugin to translate the protobuf
definition file into
stub codes for tRPC-Java
.
The core components of the translated codes are some service interfaces annotated
with @TRpcService
and @TRpcMethod
, as shown below:
// TRpcService is used to define the service name, the format of the tRPC service is a dot-seperated string start with trpc.
@TRpcService(name = "trpc.TestApp.TestServer.GreeterService")
public interface GreeterserviceAPI {
// TRpcMethod is used to define method name.
@TRpcMethod(name = "sayHello")
HelloRequestProtocol.HelloResponse sayHello(RpcContext context,
HelloRequestProtocol.HelloRequest request);
}
A service interface generated by trpc-maven-plugin
can be found
at trpc-java-demo/target/generated-sources/trpc/java/com/tencent/trpc/demo/proto/GreeterserviceAPI.java
.
In addition to regular interfaces,
trpc-maven-plugin
can also generate asynchronous interfaces. You can choose either one to use based on your requirements.
Implement the generated service interface with your own businesses, as follows:
public class GreeterServiceImpl implements GreeterserviceAPI {
@Override
public HelloRequestProtocol.HelloResponse sayHello(RpcContext context,
HelloRequestProtocol.HelloRequest request) {
// do your business
return something;
}
}
An example can be found
at trpc-java-demo/src/main/java/com/tencent/trpc/demo/server/impl/GreeterServiceImpl.java
.
The client side only needs generated service interfaces, such as GreeterserviceAPI
and GreeterserviceAsyncAPI
, and no need to implement it.
In the Quick Start guide, tRPC-Java
demonstrates programmatically configuring
the framework. However, this tutorial will focus on configuring tRPC-Java
using a YAML
configuration file.
The following YAML configuration example demonstrates the way to define a tRPC-Java
local service
in the server side:
server:
app: TestApp # App name
server: TestServer # Server name
local_ip: 127.0.0.1 # Local ip
service: # Service list
- name: trpc.TestApp.TestServer.Greeter1 # Service name
impls: # Service implement classes
- com.tencent.trpc.demo.server.impl.GreeterServiceImpl
ip: 127.0.0.1 # Listen ip
port: 12321 # Listen port
network: tcp # Network type, tcp or udp
protocol: trpc # Protocol type, default is trpc
serialization: pb # Serialization type, default is pb
transport: netty # Communication transporter, default is netty
An example can be found at trpc-java-demo/src/main/resources/trpc_java_server.yaml
.
The following YAML configuration example demonstrates the way to define a tRPC-Java
remote service
in the client side:
server: # Server config, used as caller service info
app: TestApp # App name
server: TestServer # Server name
local_ip: 127.0.0.1 # Local ip
client: # Client configs
service:
- name: trpc.TestApp.TestServer.Greeter1 # Service name
interface: com.tencent.trpc.demo.proto.GreeterserviceAPI # Service interface
naming_url: ip://127.0.0.1:12321 # Router address
network: tcp # Network type, tcp or udp
protocol: trpc # Protocol type, default is trpc
serialization: pb # Serialization type, default is pb
transport: netty # Communication transporter, default is netty
An example can be found at trpc-java-demo/src/main/resources/trpc_java_client.yaml
.
Usually, as a
tRPC-Java
application can act as both a server and a client, the above server and client configurations can be combined and defined in the same configuration file.
A more detailed YAML configuration reference can be found at YAML Configurations
After properly configured the server YAML configuration file, you can start the tRPC server with the following codes:
class Server {
public static void main(String[] args) {
TRpcSystemProperties.setProperties(TRpcSystemProperties.CONFIG_PATH, pathToServerYaml);
Main.main(args);
}
}
- An example can be found
at
trpc-java-demo/src/main/java/com/tencent/trpc/demo/example/yaml/ServerTest.java
. - To run the example codes, you can execute the following command:
$ mvn exec:java -pl :trpc-java-demo -Dexec.cleanupDaemonThreads=false -Dexec.mainClass=com.tencent.trpc.demo.example.yaml.ServerTest
After properly configured the client YAML configuration file, you can start the tRPC client with the following codes:
class Client {
public static void main(String[] args) {
TRpcSystemProperties.setProperties(TRpcSystemProperties.CONFIG_PATH, pathToServerYaml);
Main.main(args);
GreeterserviceAPI proxy = TRpcProxy.getProxy("trpc.TestApp.TestServer.Greeter1",
GreeterserviceAPI.class);
// do some test with proxy
}
}
- An example can be found
at
trpc-java-demo/src/main/java/com/tencent/trpc/demo/example/yaml/ClientTest.java
. - To run the example codes, you can execute the following command:
$ mvn exec:java -pl :trpc-java-demo -Dexec.cleanupDaemonThreads=false -Dexec.mainClass=com.tencent.trpc.demo.example.yaml.ClientTest
The earlier examples introduced the normal one-request-one-response RPC. tRPC-Java
also supports
streaming RPC, HTTP, and more.
Streaming RPC
supports more flexible interactions between clients and servers. It can be divided
into the following three modes:
- Client-side streaming: Allows the client to send multiple messages in sequence, and the server returns a message after receiving all of them. It is a many-to-one relationship.
- Server-side streaming: Allows the server to returns multiple messages for one client message. It is a one-to-many relationship.
- Bidirectional streaming: Allows the client and the server to send messages to each other in parallel. It is a many-to-many relationship.
In the stream created during the same request, the receiver receives the messages in the exact order they were sent by the requester.
Unlike normal RPCs, declaring streaming RPCs in protobuf
requires the use of the stream
keyword,
as follows:
service StreamGreeterService {
rpc clientSayHellos (stream HelloRequest) returns (HelloResponse);
rpc serverSayHellos (HelloRequest) returns (stream HelloResponse);
rpc allSayHellos (stream HelloRequest) returns (stream HelloResponse);
}
Note: Currently, it is not supported to declare both normal and streaming RPCs in the same service due to differences in their underlying implementations.
The underlying implementations of the streaming functions in tRPC-Java
are depend
on Reactor. The above protobuf
definitions may translate to the
following codes:
@TRpcService(name = "trpc.TestApp.TestServer.Greeter")
public interface StreamGreeterService {
@TRpcMethod(name = "serverSayHellos")
Flux<HelloRequestProtocol.HelloResponse> serverSayHellos(RpcContext ctx,
HelloRequestProtocol.HelloRequest request);
@TRpcMethod(name = "clientSayHellos")
Mono<HelloRequestProtocol.HelloResponse> clientSayHellos(RpcContext ctx,
Publisher<HelloRequestProtocol.HelloRequest> requests);
@TRpcMethod(name = "allSayHellos")
Flux<HelloRequestProtocol.HelloResponse> allSayHellos(RpcContext ctx,
Publisher<HelloRequestProtocol.HelloRequest> requests);
}
As the specifications of
Flux
andMono
imply, you can simply infer the stream mode by the signature of the method.
An example definition can be found at trpc-java-demo/src/main/proto/demo.proto
.
The configurations of streaming and normal RPCs are same, an example can be found
at trpc-java-demo/src/main/java/com/tencent/trpc/demo/example/stream
.
The way to run example codes is as follows:
- To run server side example:
$ mvn exec:java -pl :trpc-java-demo -Dexec.cleanupDaemonThreads=false -Dexec.mainClass=com.tencent.trpc.demo.example.stream.ServerTest
- To run client side example:
$ mvn exec:java -pl :trpc-java-demo -Dexec.cleanupDaemonThreads=false -Dexec.mainClass=com.tencent.trpc.demo.example.stream.ClientTest
To translate normal RPC to HTTP in tRPC-Java
, only the following two configuration items under
the service
configuration section need to be reconfigured:
- Change
protocol
fromtrpc
(default value) tohttp
. - Change
transporter
fromnetty
(default value) tojetty
.
An example configuration file can be found
at trpc-java-demo/src/main/resources/trpc_java_server.yaml
.
The service named with trpc.TestApp.TestServer.Greeter3
in the above example configuration file is
an HTTP service. The URL address format of a tRPC HTTP service
is /{@TRpcService.name}/{@TRpcMethod.name}
, which is the combination of the annotates. The address
of trpc.TestApp.TestServer.Greeter3
in the example file
is http://127.0.0.1:12322/trpc.TestApp.TestServer.GreeterService/sayHello
.
The following command can be used to access the above example HTTP service:
$ curl -XPOST -H"Content-Type: application/json" -d'{"message": "tRPC-Java"}' http://127.0.0.1:12322/trpc.TestApp.TestServer.GreeterService/sayHello
In addition to the basic method to access a HTTP service, tRPC-Java
supports to configure a remote
HTTP service as a tRPC client, an example can be found
at trpc-java-demo/src/main/resources/trpc_java_client.yaml
.
If you want to change the default URL address, you can add an alias option in the protobuf
definition, as follows:
import "trpc.proto";
service GreeterService2 {
rpc sayHi (HelloRequest) returns (HelloResponse) {
option (trpc.alias) = "/api/hi";
}
}
An example definition can be found at trpc-java-demo/src/main/proto/demo.proto
.
The aliased service can be accessed with the following URL:
$ curl -XPOST -H"Content-Type: application/json" -d'{"message": "tRPC-Java"}' http://127.0.0.1:12322/api/hi
tRPC-Java
is friendly to Spring Boot and other Spring environments. When using tRPC-JAVA
with
Spring Boot, the separated YAML configuration file can be replaced by the application.yml
file of
Spring Boot, as shown in example trpc-spring-server-demo/src/main/resources/application.yml
.
After properly configuring the application.yml
file, all you need to do to run a tRPC-Java
application is to add the @EnableTRpc
annotation to the Spring Boot startup class.
@EnableTRpc
@SpringBootApplication
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
An example can be found
at trpc-spring-server-demo/src/main/com/tencent/trpc/spring/demo/server/ServerApplication.java
.
If you want to integrate tRPC-Java
with SpringMVC, you can add the following dependency in
your pom.xml
:
<dependency>
<groupId>com.tencent.trpc</groupId>
<artifactId>trpc-springmvc</artifactId>
<version>${tRPC-Java.version}</version>
</dependency>
Then you can add any normal SpringMVC Controllers or tRPC-Java
services as mentioned before.
An example can be found
at trpc-spring-server-demo/src/main/com/tencent/trpc/spring/demo/server/controller/
.
Since the example codes do not add the Spring Boot plugin, you can run them as follows:
- To run server side example:
$ mvn exec:java -pl :trpc-spring-server-demo -Dexec.cleanupDaemonThreads=false -Dexec.mainClass=com.tencent.trpc.spring.demo.ServerApplication
- To run client side example:
$ mvn exec:java -pl :trpc-spring-client-demo -Dexec.cleanupDaemonThreads=false -Dexec.mainClass=com.tencent.trpc.spring.demo.ClientApplication
The normal Spring Boot application can be packaged as a single jar file, which can be run directly.
tRPC-Java
has rich scalability, you can inject various new capabilities into the RPC process
through Filter
s, and the Plugin
mechanism allows you to easily integrate new functions.
Filter
likes an onion. An RPC goes through each layer of the onion in turn. You can customize this onion
model through Filter
s.
To write a Filter, you need to implement the Filter interface firstly:
public class DemoFilter implements Filter {
@Override
public CompletionStage<Response> filter(Invoker<?> filterChain, Request req) {
try {
System.out.println("enter filter");
return filterChain.invoke(req)
.whenComplete((r, t) -> System.out.println("filter completed"));
} finally {
System.out.println("exit filter");
}
}
}
An example can be found at trpc-java-demo/src/main/com/tencent/trpc/demo/filter/DemoFilter.java
.
After writing the Filter class, you need to name and register it with
the META-INF/trpc/com.tencent.trpc.core.filter.spi.Filter
file as follows:
demoFilter=com.tencent.trpc.demo.filter.DemoFilter
After registering the Filter, you can use it by referencing its name in the YAML configuration file:
client:
filters: # The client global filters
- filter1
- filter2
service:
- name: xxx
filters: # The specified remote service filters, which are added after the client global filters
- filter3
server:
filters: # The server global filters
- filter1
- filter2
service:
- name: yyy
filters: # The specified local service filters, which are added after the server global filters
- filter3
An example can be found at trpc-java-demo/src/main/resources/trpc_java_server.yaml
.
tRPC-Java
's plugin mechanism is similar to the Java SPI mechanism, the detailed implementation can
be found
at Plugin Codes
.
The interface annotated with @Extensible
is designated as a Plugin interface, as shown below:
@Extensible
public interface WorkerPool {
// ...
}
Then, you can create a Plugin class implementing the Plugin interface and annotate it
with @Extension
, as shown below:
@Extension("thread")
public class ThreadWorkerPool implements WorkerPool {
// ...
}
After writing the Plugin class, you should provide a similar file under META-INF/trpc/
as the
examples showed before in the Filter
section.
When you want to use the Plugin, you can get the Plugin instance by using the ExtensionLoader
class as follows:
WorkerPool workerPool=ExtensionLoader.getExtensionLoader(WorkerPool.class).getExtension("thread");
// do with workerPool
- Read stub code generation tool to get deeper into
tRPC-Java
.