|
1 |
| -@@ -0,0 +1,24 @@ |
2 | 1 | # Getting Started with gRPC-Java
|
3 | 2 |
|
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 | |
5 | 7 |
|
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 |
7 | 9 |
|
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** |
12 | 11 |
|
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) |
18 | 15 |
|
19 |
| -## How to use this directory |
| 16 | +``` |
| 17 | +git clone https://github.com/grpc-ecosystem/grpc-codelabs.git |
| 18 | +``` |
20 | 19 |
|
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** |
25 | 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). |
0 commit comments