Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
version: 2
updates:

- package-ecosystem: "maven"
directories:
- "/initial"
- "/complete"
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-patch"]
schedule:
interval: "monthly"
target-branch: "main"
groups:
guide-dependencies-maven:
patterns:
- "*"

- package-ecosystem: "gradle"
directories:
- "/initial"
- "/complete"
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-patch"]
schedule:
interval: "monthly"
target-branch: "main"
groups:
guide-dependencies-gradle:
patterns:
- "*"
13 changes: 13 additions & 0 deletions .github/workflows/continuous-integration-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: CI Build

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build:
uses: spring-guides/getting-started-macros/.github/workflows/build_initial_complete_maven_gradle.yml@main
44 changes: 0 additions & 44 deletions Jenkinsfile

This file was deleted.

167 changes: 87 additions & 80 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,108 +2,62 @@
:icons: font
:source-highlighter: prettify
:project_id: gs-spring-data-reactive-redis
:java_version: 17
:build_system: maven
:build_name: demo
:build_version: 0.0.1-SNAPSHOT
:network_container: guide-redis

This guide walks you through the process of creating a functional reactive application that uses Spring Data to interact with Redis using the non-blocking Lettuce driver.

== What You Will Build

You'll build a Spring application that uses https://projects.spring.io/spring-data-redis/[Spring Data Redis] and https://projectreactor.io/[Project Reactor] to interact with a Redis data store reactively, storing and retrieving `Coffee` objects without blocking. This application uses Reactor's `Publisher` implementations based upon the Reactive Streams specification, namely `Mono` (for a Publisher returning 0 or 1 value) and `Flux` (for a Publisher returning 0 to n values).

== What You Need
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/guide_introduction.adoc[]

:java_version: 17
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/prereq_editor_jdk_buildtools.adoc[]
== Setting up the Redis Server

Before you can build a messaging application, you need to set up the server to
handle receiving and sending messages.
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/docker_compose_support.adoc[]

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/how_to_complete_this_guide.adoc[]
If you choose to run the Redis server yourself instead of using Spring Boot Docker Compose support, you have a few options:
- https://redis.io/download[Download the server] and manually run it
- Install with Homebrew, if you use a Mac
- Manually run the `compose.yaml` file with `docker compose up`

If you go with any of these alternate approaches, you should remove the `spring-boot-docker-compose` dependency from the Maven or Gradle build file.
You also need to add configuration to an `application.properties` file, as described in greater detail in the <<_preparing_to_build_the_application>> section.
As mentioned earlier, this guide assumes that you use Docker Compose support in Spring Boot, so additional changes to `application.properties` are not required at this point.

[[scratch]]
== Starting with Spring Initializr

You can use this https://start.spring.io/#!type=maven-project&language=java&packaging=jar&jvmVersion=17&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=data-redis-reactive,lombok,webflux[pre-initialized project] and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.
You can use this https://start.spring.io/#!type=maven-project&language=java&packaging=jar&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=data-redis-reactive,webflux,docker-compose[pre-initialized project] and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.

To manually initialize the project:

. Navigate to https://start.spring.io.
This service pulls in all the dependencies you need for an application and does most of the setup for you.
. Choose either Gradle or Maven and the language you want to use. This guide assumes that you chose Java.
. Click *Dependencies* and select *Spring Reactive Web*, *Spring Data Reactive Redis*, and *Lombok*.
. Click *Dependencies* and select *Spring Reactive Web*, *Spring Data Reactive Redis*, and *Docker Compose Support*.
. Click *Generate*.
. Download the resulting ZIP file, which is an archive of a web application that is configured with your choices.

NOTE: If your IDE has the Spring Initializr integration, you can complete this process from your IDE.

NOTE: You can also fork the project from Github and open it in your IDE or other editor.

[[scratch]]
== Standing up a Redis Server

Before you can build a messaging application, you need to set up the server that will
handle receiving and sending messages.

Redis is an open source, BSD-licensed, key-value data store that also comes with a
messaging system. The server is freely available at https://redis.io/download. You can
download it manually, or, if you use a Mac, with Homebrew, by running the following
command in a terminal window:

====
[source,bash]
----
brew install redis
----
====

Once you unpack Redis, you can launch it with its default settings by running the following command:

====
[source,bash]
----
redis-server
----
====

You should see a message similar to the following:

====
[source,text]
----
[35142] 01 May 14:36:28.939 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
[35142] 01 May 14:36:28.940 * Max number of open files set to 10032
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 2.6.12 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in stand alone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 35142
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | https://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'

[35142] 01 May 14:36:28.941 # Server started, Redis version 2.6.12
[35142] 01 May 14:36:28.941 * The server is now ready to accept connections on port 6379
----
====

[[initial]]
== Create a Domain Class

Create a class representing a type of coffee we wish to stock in our coffee catalog:
Create a record representing a type of coffee we wish to stock in our coffee catalog:

`src/main/java/com/example/demo/Coffee.java`
[source,java,tabsize=2]
----
include::complete/src/main/java/com/example/demo/Coffee.java[]
----

NOTE: I use Lombok in this example to eliminate the boilerplate code for constructors and so-called "data class" methods ( accessors/mutators, `equals()`, `toString()`, & `hashCode()`).


== Create a Configuration Class

Create a class that includes Spring Beans that support reactive Redis operations:
Expand All @@ -114,7 +68,6 @@ Create a class that includes Spring Beans that support reactive Redis operations
include::complete/src/main/java/com/example/demo/CoffeeConfiguration.java[]
----


== Create a Spring Bean to Load Data

Create a Spring Bean to load sample data for our application when we start it:
Expand All @@ -138,29 +91,83 @@ Create a `RestController` to provide an external interface for our application:
include::complete/src/main/java/com/example/demo/CoffeeController.java[]
----

== Run the Application

== Make the Application Executable
You can run the main method through your IDE.
Note that, if you have cloned the project from the solution repository, your IDE may look in the wrong place for the `compose.yaml` file.
You can configure your IDE to look in the correct place or you could use the command line to run the application.
The `./gradlew bootRun` and `./mvnw spring-boot:run` commands will launch the application and automatically find the compose.yaml file.

Although you can package this service as a traditional link:/understanding/WAR[WAR] file for deployment to an external application server, the simpler approach shown here creates a standalone application. You package everything in a single, executable JAR file, driven by a good old Java `main()` method. Along the way, you use Spring's support for embedding the link:/understanding/Netty[Netty] an asynchronous "container" as the HTTP runtime instead of deploying to an external instance.
== Test the Application

With the application running, run the following command from a new terminal:
[source,bash]
```
curl http://localhost:8080/coffees
```

`src/main/java/com/example/demo/DemoApplication.java`
[source,java,tabsize=2]
You should see the following output:
[source,json]
```
[
{
"id": "04ce0843-c9f8-40f6-942f-1ff643c1d426",
"name": "Jet Black Redis"
},
{
"id": "e2a0d798-5fa4-48a2-a45c-7770d8bb82bf",
"name": "Black Alert Redis"
},
{
"id": "13f13e3a-0798-44b7-8ae4-b319b227bb19",
"name": "Darth Redis"
}
]
```

== Preparing to Build the Application

To run the code without Spring Boot Docker Compose support, you need a version of Redis running locally to connect to.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove to connect to

To do this, you can use Docker Compose, but you must first make two changes to the `compose.yaml` file.
First, modify the `ports` entry in `compose.yaml` to be `'6379:6379'`.
Second, add a `container_name`.

The `compose.yaml` should now be:
----
include::complete/src/main/java/com/example/demo/DemoApplication.java[]
services:
redis:
container_name: 'guide-redis'
image: 'redis:latest'
ports:
- '6379:6379'
----

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/spring-boot-application.adoc[]
You can now run `docker compose up` to start the Redis server.
Now you should have an external Redis server that is ready to accept requests.
You can rerun the application and see the same output using your external Redis server.

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/build_an_executable_jar_subhead.adoc[]
NOTE: No configuration is required in the `application.properties` file because the default values match the Redis server configuration in `compose.yaml`. Specifically, the properties `spring.data.redis.host` and `spring.data.redis.port` default to `localhost` and `6379` respectively.

include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/build_an_executable_jar_with_both.adoc[]
include::https://raw.githubusercontent.com/spring-guides/getting-started-macros/main/build_and_execute_guide.adoc[]

== Test the Application in Docker

== Test the application
If you ran the application using a Docker instruction (shown earlier), a simple curl command from a terminal or command line will no longer work.
This is because we run our containers in a https://docs.docker.com/compose/networking/[Docker network] that is not accessible from the terminal or command line. To run curl commands, we can start a third container to run our curl commands and attach it to the same network.

Now that the application is running, you can test it by accessing `http://localhost:8080/coffees` from HTTPie, curl, or your favorite browser.
First, obtain an interactive shell to a new container that runs on the same network as the Redis container and the application:
[source, bash]
----
docker run --rm --network container:guide-redis -it alpine
----

Next, from the shell inside the container, install curl:
[source, bash]
----
apk add curl
----

Finally, you can run the curl commands as described in <<_test_the_application>>.

== Summary

Expand Down
3 changes: 1 addition & 2 deletions complete/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-docker-compose'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
}
Expand Down
5 changes: 5 additions & 0 deletions complete/compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
services:
redis:
image: 'redis:latest'
ports:
- '6379'
19 changes: 4 additions & 15 deletions complete/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
Expand All @@ -45,18 +45,7 @@

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>

</plugins>
</build>

Expand Down
11 changes: 1 addition & 10 deletions complete/src/main/java/com/example/demo/Coffee.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
package com.example.demo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Coffee {
private String id;
private String name;
public record Coffee(String id, String name) {
}
Loading