This project template is used throughout a two-hour training session for Java developers and architects who want to explore the best practices and nuances of using Spring Boot and Spring Data with Apache Ignite (or GridGain). During that instructor-led training, you build a RESTful web service that uses Apache Ignite as an in-memory database. The service is a Spring Boot application that interacts with the Ignite cluster via Spring Data repository abstractions.
Check the schedule a join one of our upcoming sessions. All the sessions are delivered by seasoned Ignite experts and committers.
- GIT command line or GitHub Desktop
- Docker Desktop
- Java Developer Kit, version 17 or later
- Apache Maven 3.6.x
- Your favorite IDE, such as IntelliJ IDEA, or Eclipse, or a simple text editor.
- Tool to query a REST endpoint such as:
- Postman REST tool
- curl
- httpie
- A web browser
This project has been tested most thoroughly using Java 17 and Ignite 3. (Apache Ignite 3 supports Java 11, but the minimum version for Spring Boot is Java 17.) Later versions may work; earlier versions will not. We test most frequently on Macs, but it should also work on Windows and Linux machines. Please create an Issue (or a PR!) if you find any issues.
This project currently uses Spring Boot and Data 3.x. Ignite and GridGain are expected to support Spring 4.x soon.
Open a terminal window and clone the project to your dev environment:
git clone https://github.com/GridGain-Demos/spring-data-training.git-
Start your nodes using Docker Compose. Using Apache Ignite 3:
docker compose -f docker-compose.yml up -d
Or GridGain 9:
docker compose -f docker-compose-gg9.yml up -d
-
Initialize your cluster:
a. Start the Command Line Interface (CLI). Using Apache Ignite 3:
docker run -v ./config/world.sql:/opt/ignite/downloads/world.sql --rm --network spring-boot-data-training_default -it apacheignite/ignite:3.1.0 cli
Or GridGain 9:
docker run -v ./gridgain-license.json:/opt/ignite/downloads/gridgain-license.json -v ./config/world.sql:/opt/ignite/downloads/world.sql --rm --network spring-boot-data-training_default -it gridgain/gridgain9:9.1.8 cli
(Ensure your license file is in your current directory.)
b. Connect to the cluster.
connect http://node1:10300
c. Execute command to initialize the cluster. Using Apache Ignite 3:
cluster init --name=spring-data-training --metastorage-group=node1,node2
Or GridGain 9:
cluster init --name=spring-data-training --metastorage-group=node1,node2 --license=/opt/ignite/downloads/gridgain-license.json
Leave the CLI connected to the cluster.
-
In the same CLI window, load the media store database by executing the SQL command to load the sample data.
sql --file=/opt/ignite/downloads/world.sql
-
Enable Ignite Spring Boot and Spring Data extensions by adding the following artifacts to the
pom.xmlfile<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>${ignite.project}</groupId> <artifactId>spring-data-ignite</artifactId> <version>${ignite.version}</version> </dependency> <dependency> <groupId>${ignite.project}</groupId> <artifactId>spring-boot-starter-ignite-client</artifactId> <version>${ignite.version}</version> </dependency>
-
If you're using GridGain rather than Apache Ignite, update the
ignite.projectproperty toorg.gridgainand theignite.versionto the correct version of GridGain,9.1.8for example -
Configure Spring Data to speak the right SQL dialect. Create a file
resources/META-INF/spring.factoriesand add the following parameter:org.springframework.data.jdbc.repository.config.DialectResolver$JdbcDialectProvider=org.apache.ignite.data.IgniteDialectProvider
-
Update the
application.propertiesby adding an option that tells Spring Boot where to find the Ignite server node:ignite.client.addresses=127.0.0.1:10800 spring.datasource.url=jdbc:ignite:thin://localhost:10800/ spring.datasource.driver-class-name=org.apache.ignite.jdbc.IgniteJdbcDriver
-
Edit the
Application.javaclass. Autowire our connection to the Ignite servers:@Autowired private Ignite ignite;
-
Add some diagnostics code to run when the server starts:
private Logger log = LoggerFactory.getLogger(Application.class); @EventListener(ApplicationReadyEvent.class) public void startupLogger() { log.info("Table names existing in cluster: {}", ignite.tables().tables().stream().map(Table::name).toList()); log.info("Node information:"); for (var n : ignite.cluster().nodes()) { log.info("ID: {}, Name: {}, Address: {}", n.id(), n.name(), n.address()); } }
-
Run your new Spring Boot application. It should connect to your Ignite servers and list information about the tables and cluster topology
-
Create the
CountryRepositoryclass (in thecom.gridgain.training.springpackage):@Repository public interface CountryRepository extends CrudRepository<Country, String> { }
-
Add a method that returns countries with a population bigger than provided one:
List<Country> findByPopulationGreaterThanOrderByPopulationDesc(int population);
-
Add a test in ApplicationTests (in the
src/testfolder) that validates that the method returns a non-empty result:@Test void countryRepositoryWorks() { var results = countryRepository.findByPopulationGreaterThanOrderByPopulationDesc(100_000_000); System.out.println("count=" + results.size()); Assertions.assertTrue(results.size() > 0); }
Add the following line after ApplicationTests class declaration:
@Autowired CountryRepository countryRepository;
-
Run the tests:
mvn compile test
-
Create the
CityRepositoryclass (in thecom.gridgain.training.springpackage) :@Repository public interface CityRepository extends CrudRepository<City, Integer> { }
-
Add a direct SQL query that joins two tables:
record PopulousCity(String cityName, Integer population, String countryName) {} @Query("SELECT city.name as city_name, MAX(city.population) as population, country.name as country_name FROM country " + "JOIN city ON city.countrycode = country.code " + "GROUP BY city.name, country.name, city.population " + "ORDER BY city.population DESC LIMIT :limit") public List<PopulousCity> findTopXMostPopulatedCities(int limit);
-
Create a test in ApplicationTests to validate the methods respond properly:
@Test void cityRepositoryWorks() { var city = cityRepository.findById(34); Assertions.assertTrue(city.isPresent()); Assertions.assertEquals("Tirana", city.get().getName()); var populatedCities = cityRepository.findTopXMostPopulatedCities(5); Assertions.assertEquals(5, populatedCities.size()); Assertions.assertEquals("Mumbai (Bombay)", populatedCities.get(0).cityName()); }
Add the following line after ApplicationTests class declaration:
@Autowired CityRepository cityRepository;
-
Run the tests:
mvn compile test
In this section, we'll bring together the REST end-points supported by Spring Boot and the database access provided by Spring Data. By starting Ignite and loading the data (as mentioned in the above steps), this code can be directly used for the REST APIs.
-
Create a REST Controller for the application by creating a new class named
WorldDatabaseController(in thecom.gridgain.training.springpackage) with the following contents:@RestController public class WorldDatabaseController { @Autowired CityRepository cityRepository; }
-
Add a method that returns top X most populated cities:
@GetMapping("/api/mostPopulated") public List<CityRepository.PopulousCity> getMostPopulatedCities(@RequestParam(value = "limit", required = false, defaultValue = "10") Integer limit) { return cityRepository.findTopXMostPopulatedCities(limit); }
-
Restart the
Applicationand then test the controller method either in REST endpoint viewer: http://localhost:8080/api/mostPopulated?limit=5
When you have finished the exercises, you can shut down your cluster.
-
Shut down the client application in your IDE
-
Shut down your cluster with the following command if you're using Apache Ignite:
docker compose -f docker-compose.yaml down
Or if you're using GridGain:
docker compose -f docker-compose-gg9.yaml down
The "down" command shuts down and deletes the containers. You can also use the "stop" command, which stops the cluster but keeps the containers, meaning that they can be restarted.