Skip to content

Commit 31c6fa1

Browse files
README.md files with walkthroughs (#32)
Co-authored-by: Sergii Tkachenko <[email protected]>
1 parent bf065e9 commit 31c6fa1

File tree

2 files changed

+910
-37
lines changed

2 files changed

+910
-37
lines changed
Lines changed: 364 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,372 @@
1-
@@ -0,0 +1,24 @@
21
# Getting Started with gRPC-Java
32

4-
Get hands-on with gRPC for Java in this interactive codelab! <!-- TODO(larry-safran): Insert link once codelab is published. -->
3+
|||
4+
| :---- | :---- |
5+
| Summary | Get hands-on with gRPC for Java in this interactive codelab\! Perfect for Java developers new to gRPC, those seeking a refresher, or anyone building distributed systems. No prior gRPC experience needed\! |
6+
| **URL** | devsite/codelabs/docs |
57

6-
Perfect for Java developers new to gRPC, those seeking a refresher, or anyone building distributed systems. No prior gRPC experience needed!
8+
# Before you begin
79

8-
#### Build a complete gRPC service from scratch, learning:
9-
- Protocol Buffers (protobuf): Define service contracts & data.
10-
- gRPC Code Generation: Auto-generate Java code.
11-
- Client/Server Communication: Implement seamless interactions.
10+
## **Prerequisites**
1211

13-
#### You'll gain:
14-
- A working gRPC service in Java.
15-
- Hands-on experience with Protocol Buffers and code generation.
16-
- Skills to design, build, & test gRPC clients and servers.
17-
- A strong foundation in gRPC for real-world projects.
12+
* [JDK](https://jdk.java.net/) version 8 or higher
13+
* We recommend [openjdk temurin v21](https://cloud.google.com/java/docs/setup\#install\_a\_jdk\_java\_development\_kit)
14+
* Clone the [grpc codelab repo](https://github.com/grpc-ecosystem/grpc-codelabs.git)
1815

19-
## How to use this directory
16+
```
17+
git clone https://github.com/grpc-ecosystem/grpc-codelabs.git
18+
```
2019

21-
- [start_here](start_here/) directory serves as a starting point for the
22-
codelab.
23-
- [complete](complete/) directory showcases the finished code, giving you a peak
24-
of how the final implementation should look like.
20+
## **What you’ll learn**
2521

22+
* Get hands-on with gRPC for Java in this interactive codelab\! Perfect for Java developers new to gRPC, those seeking a refresher, or anyone building distributed systems. No prior gRPC experience needed\!
23+
* Build a complete gRPC service from scratch, learning:
24+
* Protocol Buffers (protobuf): Define service contracts & data.
25+
* gRPC Code Generation: Auto-generate Java code.
26+
* Client/Server Communication: Implement seamless interactions.
27+
* Testing & Debugging: Ensure reliability & correctness.
28+
* You'll gain:
29+
* A working gRPC service in Java.
30+
* Hands-on experience with Protocol Buffers and code generation.
31+
* Skills to design, build, & test gRPC clients and servers.
32+
* A strong foundation in gRPC for real-world projects.
33+
34+
## **What you’ll need**
35+
36+
* A computer with internet connection
37+
38+
---
39+
40+
# Setup
41+
42+
[Download](https://download-directory.github.io/?url=https%3A%2F%2Fgithub.com%2Fgrpc-ecosystem%2Fgrpc-codelabs%2Ftree%2Fmain%2Fcodelabs%2FGetting\_Started\_with\_gRPC\_Java) the codelab or Clone the codelab repo, if you haven’t yet done so.
43+
To download without using git:
44+
45+
* go to [https://github.com/grpc-ecosystem/grpc-codelabs.git](https://github.com/grpc-ecosystem/grpc-codelabs.git)
46+
* click on \`\<\> Code\`
47+
* select \`Download ZIP\`
48+
49+
Change directory to `codelabs/grpc-java-getting-started/start_here`
50+
51+
Tip: For complete versions of each of the files we are editing, look in the `../complete` directory
52+
53+
# Define proto
54+
55+
Duration: 5:00
56+
57+
Our first step is to define the gRPC *service* and the method *request* and *response* types using [protocol buffers](https://protobuf.dev/overview).
58+
59+
Let’s create a `route_guide.proto` file.
60+
We’ve given you some boiler plate to start with in `src/main/proto/routeguide/route_guide.proto`
61+
62+
Since we’re generating Java code in this example, we’ve specified a `java_package` file option and a name for the Java class in our `.proto`:
63+
64+
```
65+
option java_package = "io.grpc.examples.routeguide";
66+
option java_outer_classname = "RouteGuideProto";
67+
```
68+
69+
## **Define proto Message**
70+
71+
Our `.proto` file contains protocol buffer message type definitions for all the request and response types used in our service methods.
72+
73+
Let’s define the `Point` message type (`a latitude and a longitude, both multiplied by 10**7`):
74+
75+
```
76+
// Points are represented as latitude-longitude pairs in the E7 representation(degrees times 10**7).
77+
// Latitudes should be in the range +/- 90 degrees.
78+
// Longitude should be in the range +/- 180 degrees.
79+
80+
message Point {
81+
int32 latitude = 1;
82+
int32 longitude = 2;
83+
}
84+
```
85+
86+
Let’s also define the `Feature` message type (`A feature names something at a given point`):
87+
88+
```
89+
// A feature names something at a given point.
90+
//
91+
// If a feature could not be named, the name is empty.
92+
93+
message Feature {
94+
// The name of the feature.
95+
string name = 1;
96+
97+
// The point where the feature is detected.
98+
Point location = 2;
99+
}
100+
```
101+
102+
## **Define RouteGuide service**
103+
104+
To define a service, you specify a named service in your `.proto` file:
105+
106+
```
107+
service RouteGuide {
108+
// Definition of the service goes here
109+
}
110+
```
111+
112+
## **Define RPC Method**
113+
114+
Then you define `rpc` methods inside your service definition, specifying their request and response types. In this section of the codelab, let’s define
115+
116+
* A Unary RPC method \- A *simple RPC* where the client sends a request to the server using the stub and waits for a response to come back, just like a normal function call.
117+
118+
```
119+
// Obtains the feature at a given position.
120+
rpc GetFeature(Point) returns (Feature) {}
121+
```
122+
123+
---
124+
125+
# Generating client and server code
126+
127+
Next we need to generate the gRPC client and server interfaces from our .proto service definition. We do this using the protocol buffer compiler `protoc` with a special gRPC Java plugin. You need to use the [proto3](https://github.com/google/protobuf/releases) compiler (which supports both proto2 and proto3 syntax) in order to generate gRPC services.
128+
129+
When using Gradle or Maven, the protoc build plugin can generate the necessary code as part of the build. You can refer to the [grpc-java README](https://github.com/grpc/grpc-java/blob/master/README.md) for how to generate code from your own `.proto` files.
130+
131+
We have provided Gradle configuration.
132+
133+
134+
| Note: You may need to do `chmod +x ../gradlew` if you downloaded a zip instead of doing `git clone`. |
135+
| :---- |
136+
137+
From the `start_here` directory enter
138+
139+
```
140+
../gradlew build
141+
```
142+
143+
The following classes are generated from our service definition:
144+
145+
* `Feature.java`, `Point.java` and others which contain all the protocol buffer code to populate, serialize, and retrieve our request and response message types.
146+
* `RouteGuideGrpc.java` which contains (along with some other useful code):
147+
* a base class for `RouteGuide` servers to implement, `RouteGuideGrpc.RouteGuideImplBase`, with all the methods defined in the `RouteGuide` service
148+
* Stub classes for clients to use
149+
150+
---
151+
152+
# Creating the server
153+
154+
Duration: 5:00
155+
156+
First let’s look at how we create a `RouteGuide` server. There are two parts to making our `RouteGuide` service do its job:
157+
158+
* Implementing the service interface generated from our service definition: doing the actual “work” of our service.
159+
* Running a gRPC server to listen for requests from clients and dispatch them to the right service implementation.
160+
161+
## **Implementing RouteGuide**
162+
163+
As you can see, our server has a `RouteGuideService` class that extends the generated `RouteGuideGrpc.RouteGuideImplBase` abstract class:
164+
165+
```java
166+
private static class RouteGuideService extends RouteGuideGrpc.RouteGuideImplBase {
167+
...
168+
}
169+
```
170+
171+
We have provided the following 2 files for initializing your server with features
172+
`./src/main/java/io/grpc/examples/routeguide/RouteGuideUtil.java`
173+
`./src/main/resources/io/grpc/examples/routeguide/route_guide_db.json`
174+
175+
Let us look into a simple RPC implementation in detail
176+
177+
### **Unary RPC**
178+
179+
`RouteGuideService` implements all our service methods, in this case it is just `GetFeature()`, which just gets a `Point` from the client and returns the corresponding feature information from its database in a `Feature`.
180+
We include `checkFeature`. The most important aspect is creating a `Feature` object
181+
182+
**Feature.newBuilder().setName("").setLocation(location).build();**| // Creates a feature.
183+
---|---
184+
185+
```java
186+
@Override
187+
public void getFeature(Point request, StreamObserver<Feature> responseObserver) {
188+
responseObserver.onNext(checkFeature(request));
189+
responseObserver.onCompleted();
190+
}
191+
```
192+
193+
The `getFeature()` method takes two parameters:
194+
195+
* `Point`: the request
196+
* `StreamObserver<Feature>`: a response observer, which is a special interface for the server to call with its response.
197+
198+
To return our response to the client and complete the call:
199+
200+
1. We construct and populate a `Feature` response object to return to the client, as specified in our service definition. In this example, we do this in a separate private `checkFeature()` method.
201+
2. We use the response observer’s `onNext()` method to return the `Feature`.
202+
3. We use the response observer’s `onCompleted()` method to specify that we’ve finished dealing with the RPC.
203+
204+
---
205+
206+
# Starting the gRPC server
207+
208+
Duration: 5:00
209+
210+
Once we’ve implemented all our service methods, we need to start up a gRPC server so that clients can actually use our service. We include in our boilerplate the creation of the ServerBuilder object:
211+
212+
`ServerBuilder.forPort(port), port, RouteGuideUtil.parseFeatures(featureFile)`
213+
214+
We build the service in the constructor:
215+
216+
1. Specify the port we want to use to listen for client requests using the builder’s `forPort()` method (it will use the wildcard address).
217+
2. Create an instance of our service implementation class `RouteGuideService` and pass it to the builder’s `addService()` method.
218+
3. Call `build()` on the builder to create an RPC server for our service.
219+
220+
The following snippet shows how we create a `ServerBuilder` object.
221+
222+
223+
```java
224+
this(Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()),
225+
port, RouteGuideUtil.parseFeatures(featureFile));
226+
```
227+
228+
The following snippet shows how we create a server object for our `RouteGuide` service.
229+
230+
```java
231+
/** Create a RouteGuide server using serverBuilder as a base and features as data. */
232+
public RouteGuideServer(ServerBuilder<?> serverBuilder, int port, Collection<Feature> features) {
233+
this.port = port;
234+
server = serverBuilder.addService(new RouteGuideService(features))
235+
.build();
236+
}
237+
```
238+
239+
Implement a start method that calls `start` on the server we created above
240+
241+
```java
242+
public void start() throws IOException {
243+
server.start();
244+
logger.info("Server started, listening on " + port);
245+
}
246+
```
247+
248+
Implement a method to wait for the server to complete so it doesn’t immediately exit.
249+
250+
```java
251+
/** Await termination on the main thread since the grpc library uses daemon threads. */
252+
private void blockUntilShutdown() throws InterruptedException {
253+
if (server != null) {
254+
server.awaitTermination();
255+
}
256+
}
257+
```
258+
259+
As you can see, we build and start our server using a `ServerBuilder`.
260+
261+
In the main method we
262+
263+
1. Create a `RouteGuideServer` instance
264+
2. Call `start()` to activate an RPC server for our service.
265+
3. Wait for the service to be stopped by calling `blockUntilShutdown()`
266+
267+
```java
268+
public static void main(String[] args) throws Exception {
269+
RouteGuideServer server = new RouteGuideServer(8980);
270+
server.start();
271+
server.blockUntilShutdown();
272+
}
273+
```
274+
275+
---
276+
277+
# Creating the client
278+
279+
Duration: 5:00
280+
281+
In this section, we’ll look at creating a client for our `RouteGuide` service. You can see our complete example client code in ../complete/src/main/java/io/grpc/examples/routeguide/RouteGuideClient.java
282+
283+
## **Instantiating a stub**
284+
285+
To call service methods, we first need to create a *stub*. There are two types of stubs, but we only need to use the blocking one for this codelab. The 2 types are:
286+
287+
* a *blocking/synchronous* stub: this means that the RPC call waits for the server to respond, and will either return a response or raise an exception.
288+
* a *non-blocking/asynchronous* stub that makes non-blocking calls to the server, where the response is returned asynchronously. You can make certain types of streaming calls only by using the asynchronous stub.
289+
290+
First we need to create a gRPC *channel* and then use the channel to create our stub.
291+
292+
We could have used a `ManagedChannelBuilder` directly to create the channel.
293+
294+
```java
295+
ManagedChannelBuilder.forAddress(host, port).usePlaintext().build
296+
```
297+
298+
But let’s use a utility method that takes a string with `hostname:port`
299+
300+
```java
301+
Grpc.newChannelBuilder(target, InsecureChannelCredentials.create()).build();
302+
```
303+
304+
Now we can use the channel to create our blocking stub. For this codelab, we only have blocking RPCs, so we use the `newBlockingStub` method provided in the `RouteGuideGrpc` class we generated from our `.proto`.
305+
306+
```java
307+
blockingStub = RouteGuideGrpc.newBlockingStub(channel);
308+
```
309+
310+
## **Calling service methods**
311+
312+
Now let’s look at how we call our service methods.
313+
314+
### **Simple RPC**
315+
316+
Calling the simple RPC `GetFeature` is nearly as straightforward as calling a local method.
317+
318+
We create and populate a request protocol buffer object (in our case `Point`), pass it to the `getFeature()` method on our blocking stub, and get back a `Feature`.
319+
320+
If an error occurs, it is encoded as a `Status`, which we can obtain from the `StatusRuntimeException`.
321+
322+
```java
323+
Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build();
324+
325+
Feature feature;
326+
try {
327+
feature = blockingStub.getFeature(request);
328+
} catch (StatusRuntimeException e) {
329+
logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
330+
return;
331+
}
332+
```
333+
334+
The boilerplate logs a message containing the contents based on whether or not there was a feature at the specified point.
335+
336+
---
337+
338+
# Try it out\!
339+
340+
Duration: 2:00
341+
342+
## **To build the codelab**
343+
344+
1. From the `start_here` directory:
345+
346+
```
347+
$ ../gradlew installDist
348+
```
349+
350+
This will compile your code, package it in a jar and create the scripts that run the example. They will be created in the `build/install/start_here/bin/` directory. The scripts are: `route-guide-server` and `route-guide-client`.
351+
352+
The server needs to be running before starting the client.
353+
354+
2. Run the server:
355+
356+
```
357+
$ ./build/install/start_here/bin/route-guide-server
358+
```
359+
360+
3. Run the client:
361+
362+
```
363+
$ ./build/install/start_here/bin/route-guide-client
364+
```
365+
366+
---
367+
368+
# What’s next
369+
370+
* Do the streaming code lab gRPC Java Streaming (../../grpc-java-streaming)
371+
* Learn how gRPC works in [Introduction to gRPC](https://grpc.io/docs/what-is-grpc/introduction/) and [Core concepts](https://grpc.io/docs/what-is-grpc/core-concepts/).
372+
* Explore the [API reference](https://grpc.io/docs/languages/java/api).

0 commit comments

Comments
 (0)