Skip to content

Latest commit

 

History

History
485 lines (363 loc) · 17.1 KB

2.basic_tutorial.md

File metadata and controls

485 lines (363 loc) · 17.1 KB

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.

Add dependency

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 the tRPC-Java repository.

Define Service

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.

Write Client and Server Code

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.

Configuration

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);
    }
}
  1. An example can be found at trpc-java-demo/src/main/java/com/tencent/trpc/demo/example/yaml/ServerTest.java.
  2. 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
    }
}
  1. An example can be found at trpc-java-demo/src/main/java/com/tencent/trpc/demo/example/yaml/ClientTest.java.
  2. 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

Other Supported Protocols

The earlier examples introduced the normal one-request-one-response RPC. tRPC-Java also supports streaming RPC, HTTP, and more.

Streaming RPC

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 and Mono 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

Translate normal RPC to HTTP

To translate normal RPC to HTTP in tRPC-Java, only the following two configuration items under the service configuration section need to be reconfigured:

  1. Change protocol from trpc(default value) to http.
  2. Change transporter from netty(default value) to jetty.

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

Spring Boot integration and SpringMVC

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.

Filter and Plugin

tRPC-Java has rich scalability, you can inject various new capabilities into the RPC process through Filters, and the Plugin mechanism allows you to easily integrate new functions.

Filter

Filter likes an onion. An RPC goes through each layer of the onion in turn. You can customize this onion model through Filters.

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.

Plugin

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

What's Next