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 GridGain 9.1.8. (GridGain 9 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. GridGain 9.1.19 and higher supports Spring 4.x.
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:
docker compose up -d
-
Initialize your cluster:
a. Start the Command Line Interface (CLI):
docker run -v ./gridgain-license.json:/opt/gridgain/downloads/gridgain-license.json -v ./config/world.sql:/opt/gridgain/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:
cluster init --name=spring-data-training --metastorage-group=node1,node2,node3 --license=/opt/gridgain/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/gridgain/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>
-
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 GridGain 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:
docker compose -f docker-compose.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.