|
1 | 1 | # Getting Started with gRPC-Java |
2 | 2 |
|
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 | |
| 3 | +Get hands-on with gRPC for Java in this interactive codelab! |
7 | 4 |
|
8 | | -# Before you begin |
| 5 | +Perfect for Java developers new to gRPC, those seeking a refresher, or anyone |
| 6 | +building distributed systems. No prior gRPC experience needed! |
9 | 7 |
|
10 | | -## **Prerequisites** |
| 8 | +### How to use this directory |
11 | 9 |
|
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) |
| 10 | +- [start_here](./start_here/) directory serves as a starting point for the codelab. |
| 11 | +- [completed](./completed/) directory showcases the finished code, giving you a peak of how the |
| 12 | + final implementation should look like. |
15 | 13 |
|
16 | | -``` |
17 | | -git clone https://github.com/grpc-ecosystem/grpc-codelabs.git |
18 | | -``` |
| 14 | +## Codelab |
19 | 15 |
|
20 | | -## **What you’ll learn** |
21 | | - |
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). |
| 16 | +Follow the codelab at: |
| 17 | +https://codelabs.developers.google.com/grpc/getting-started-grpc-java |
0 commit comments