Developer Guides Getting Started Getting Started What is a Graph Database? Intro to Graph DBs Video Series Concepts: RDBMS to Graph Concepts: NoSQL to Graph Getting Started Resources Neo4j Graph Platform Graph Platform Overview Neo4j Desktop Intro Neo4j Browser Intro… Read more →

Developer Guides

Want to Speak? Get $ back.

Neo4j Java Driver Spring Boot Starter

Intro

What’s in the box?

The Neo4j Java Driver Spring Boot starter provides both a Spring Boot autoconfigure and a starter module. The autoconfigure module adds a single instance of org.neo4j.driver.Driver as a bean to the Spring Context if there is none and registers health- and metric endpoints for all Driver-beans if the necessary Spring infrastructure is in place.

It does not bring any mapping facilities in addition the available functions of the driver nor Spring Data integration. Have a look at Spring Data Neo4j⚡️RX for reactive Spring Data Neo4j repositories.

The driver instance is a long living object that provides short living sessions as needed. The instance does not need to be closed manually, that is done automatically when the application shuts down. There is no need for external connection pooling. This is done already in the driver and can be configured via properties. Please have a look at the chapter Sessions and transactions.

Do I need the Neo4j Java Driver Spring Boot starter?

We recommend this starter for all new Spring Boot applications that want to use our new generation of drivers (“4.0”). The next generation of drivers is compatible with both 4.0.x and 3.5.x community and enterprise databases. The starter takes away all the boilerplate code of configuring an instance of the driver and does support externalized configuration for all aspects of the driver.

  • You want to work directly with a 4.0 driver? The starter is for you.
  • You want Spring Data Neo4j⚡️RX repositories? The automatic configuration for SDN-RX is dependent on this starter, so it is already there and you would use exactly the same as described in this manual to configure your connection
  • You have the previous generation of Spring Data Neo4j or Neo4j-OGM? While you cannot use the 4.0.x line of this starter, as Spring Data Neo4j + OGM is based on the previous generation of the Java driver, you can use the 1.7.x line of this starter. This configures a bean of the previous generation of the Neo4j driver and also configures Neo4j-OGM to use that bean instead of an internal one.

Does it work with the 1.7 series of the driver?

The 1.7.x line of the starter is for the 1.7.x line of the driver, the 4.0.x line for the 4.0..x of the driver.

Does it work with the embedded database?

No.

What’s with the long name?

neo4j-java-driver-spring-boot-starter is quite a long name for a module, we get that. However, it follows the official Spring Boot convention described here.



As a rule of thumb, you should name a combined module after the starter. For example, assume that you are creating a starter for “acme” and that you name the auto-configure module acme-spring-boot-autoconfigure and the starter acme-spring-boot-starter. If you only have one module that combines the two, name it acme-spring-boot-starter.



Our “acme” module is the Neo4j Java Driver, project name neo4j-java-driver and things add up from there, that’s all.

Getting started

As with any other Spring Boot starter, the only thing you have to do is to include the starter module via your dependency management. If you don’t configure anything, than the starter assumes bolt://localhost:7687 as Neo4j URI and a server that has disabled authentication.

If only a single URI is provided, than the configuration tries to use that. Otherwise, it passes all URIs to the Java driver which in turn uses the first one that is a reachable bolt+routing instance.

The automatic configuration will fail fast if the driver cannot connect to a single Neo4j database or to a routing server.

The Neo4j driver supports three different programming models:

  • Blocking database access (much like standard JDBC)
  • Asynchronous programming based on JDKs completable futures and related infrastructure
  • Reactive programming based on Reactive Streams

Those are all included in the same binary. The reactive programming model however requires a 4.0 Neo4j server on the database side and reactive Spring on the other hand. To make the following intro as accessible as possible, we only display the blocking database access. Have a look at the examples directory for a reactive web application example.

Preparing the database

For this example, we stay within the movie graph, as it comes for free with every Neo4j instance.

If you don’t have a running database but Docker installed, please run:

Start a local Neo4j instance inside Docker.
docker run --publish=7474:7474 --publish=7687:7687 neo4j:3.5.8

You know can access http://localhost:7474. At first visit, you have to change your password. We chose secret in the examples. Note the command ready to run in the prompt. Execute it to fill your database with some test data.

Create a new Spring Boot project

The easiest way to setup a Spring Boot project is start.spring.io (which is integrated in the major IDEs as well, in case you don’t want to use the website).

Select the “Spring Web Starter” to get all the dependencies needed for creating a Spring based web application. The Spring Initializr will take care of creating a valid project structure for you, with all the files and settings in place for the selected build tool.

Don’t choose Spring Data Neo4j here, as it will get you the previous generation of Spring Data Neo4j including OGM and additional abstraction over the driver.

Maven

You can issue a CURL request against the Spring Initializer to create a basic Maven project:

Create a basic Maven project with the Spring Initializr
curl https://start.spring.io/starter.tgz \
  -d dependencies=web,actuator \
  -d bootVersion=2.1.7.RELEASE \
  -d baseDir=Neo4jSpringBootExample \
  -d name=Neo4j%20SpringBoot%20Example | tar -xzvf -

This will create a new folder Neo4jSpringBootExample. As this starter is not yet on the initializer, you’ll have to add the following dependency manually to your pom.xml:

Inclusion of the neo4j-java-driver-spring-boot-starter in a Maven project
<dependency>
	<groupId>org.neo4j.driver</groupId>
	<artifactId>neo4j-java-driver-spring-boot-starter</artifactId>
	<version>4.0.0-beta01</version>
</dependency>

You would also add the dependency manually in case of an existing project.

Gradle

The idea is the same, just generate a Gradle project:

Create a basic Gradle project with the Spring Initializr
curl https://start.spring.io/starter.tgz \
  -d dependencies=web,actuator \
  -d type=gradle-project \
  -d bootVersion=2.1.7.RELEASE \
  -d baseDir=Neo4jSpringBootExampleGradle \
  -d name=Neo4j%20SpringBoot%20Example | tar -xzvf -

The dependency for Gradle looks like this and must be added to build.gradle:

Inclusion of the neo4j-java-driver-spring-boot-starter in a Gradle project
dependencies {
    compile 'org.neo4j.driver:neo4j-java-driver-spring-boot-starter:4.0.0-beta01'
}

You would also add the dependency manually in case of an existing project.

Configuration

Now open any of those projects in your favorite IDE. Find application.properties and configure your Neo4j credentials:

org.neo4j.driver.uri=bolt://localhost:7687
org.neo4j.driver.authentication.username=neo4j
org.neo4j.driver.authentication.password=secret

This is the bare minimum of what you need to connect to a Neo4j instance.

Refer to the list of configuration properties for all options this driver supports.

While the above configuration is presented in the easiest format (an application.properties file), you are of course free to use any other declarative way to define properties in Spring Boot. Please checkout the chapter Externalized Configuration.

It is not necessary to add any programmatically configuration of the driver when you use this starter. While it may work, we strongly discourage and don’t support additional, pragmatical configuration of the Neo4j driver when using this starter.

Example CRUD Controller

Add the following @RESTController to your application:

MovieController.java
package com.example.demo;

import java.util.List;

import org.neo4j.driver.AccessMode;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Session;
import org.neo4j.driver.SessionConfig;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MoviesController {

	private final Driver driver; (1)

	public MoviesController(Driver driver) { (2)
		this.driver = driver;
	}

	@GetMapping(path = "/movies", produces = MediaType.APPLICATION_JSON_VALUE) (3)
	public List<String> getMovieTitles() {

		try (Session session = driver.session()) { (4)
			return session.run("MATCH (m:Movie) RETURN m ORDER BY m.name ASC")
				.list(r -> r.get("m").asNode().get("title").asString());
		}
	}
}
1 An instance field to hold the driver
2 The driver is injected via constructor injection
3 A mapping to the url /movies
4 Using the driver to get a short lived session and issue a query on it

If you generated your application via the commands given above, you can now run the class Neo4jSpringBootExampleApplication and after a short while, you can access http://localhost:8080/movies.

Logging

The Neo4j Spring Boot starter uses a small shim to integrate the driver with Springs JCL abstraction. Thus, all logging configuration can be done via Spring Boot’s application.properties. Important names used for logging are:

logging.level.org.neo4j.driver.GraphDatabase = debug
logging.level.org.neo4j.driver.Driver = debug

If you ever have the need to debug outgoing and incoming Bolt messages, use those two names:

logging.level.org.neo4j.driver.OutboundMessageHandler = debug
logging.level.org.neo4j.driver.InboundMessageDispatcher = debug
The prefix org.neo4j.driver is specific to the Drivers integration with Spring Boot.

Production-ready features

The Neo4j Spring Boot starter hooks into Spring Boot’s Production-ready features (or the so called Spring Boot Actuator). This happens automatically when you add the Spring Boot Actuator Starter like this:

Spring Boot Starter Actuator dependency with Maven
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

or with Gradle:

Spring Boot Starter Actuator dependency with Gradle
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-actuator'
}

We support both the health- and metrics-actuator.

Health information

Both reactive and imperative health checks are available, with the reactive health checks having precedence when Project Reactor is detected.

When calling the health endpoint /actuator/health and the driver can reach a Neo4j instance, an unauthenticated user will see

Health information
{
  "status": "UP"
}

and an authenticated user will see

Health information
{
  "status": "UP",
  "details": {
    "neo4j": {
      "status": "UP",
      "details": {
        "server": "Neo4j/4.0.0@localhost(127.0.0.1):7687",
        "database": "neo4j"
      }
    }
  }
}

In case no instance is reachable, the status will be DOWN and the details carry the error message.

To disable the Neo4j health indicator, use the standard Spring Boot property management.health.neo4j.enabled with a value of false.

Driver metrics

neo4j-java-driver-spring-boot-starter comes with support for Micrometer metrics out of the box. It detects Micrometer on the classpath and binds the metrics of all instances of org.neo4j.driver.Driver, that have enabled their metrics, to a micrometer registry.

To enable metrics for the driver instance provided by this starter, set org.neo4j.driver.config.metrics-enabled to true.

The following metrics are exposes

  • neo4j.driver.connections.inUse (Gauge)
  • neo4j.driver.connections.timedOutToAcquire (Counter)
  • neo4j.driver.connections.closed (Counter)
  • neo4j.driver.connections.failedToCreate (Counter)
  • neo4j.driver.connections.created (Counter)
  • neo4j.driver.connections.idle (Gauge)
  • neo4j.driver.connections.acquired (Counter)

All metrics will have the tags name (the bean of the driver they belong to) and poolId (the id of the connection pool, that contributed to the corresponding counter or gauge).

Configuration options

Key Default Value Description

org.neo4j.driver.authentication.kerberos-ticket

A kerberos ticket for connecting to the database. Mutual exclusive with a given username.

org.neo4j.driver.authentication.password

The password of the user connecting to the database.

org.neo4j.driver.authentication.realm

The realm to connect to.

org.neo4j.driver.authentication.username

The login of the user connecting to the database.

org.neo4j.driver.pool.connection-acquisition-timeout

1m

Acquisition of new connections will be attempted for at most configured timeout.

org.neo4j.driver.config.connection-timeout

5s

Specify socket connection timeout.

org.neo4j.driver.config.encrypted

true

Flag, if the driver should use encrypted traffic.

org.neo4j.driver.pool.idle-time-before-connection-test

Pooled connections that have been idle in the pool for longer than this timeout will be tested before they are used again.

org.neo4j.driver.pool.log-leaked-sessions

false

Flag, if leaked sessions logging is enabled.

org.neo4j.driver.pool.max-connection-lifetime

1h

Pooled connections older than this threshold will be closed and removed from the pool.

org.neo4j.driver.pool.max-connection-pool-size

100

The maximum amount of connections in the connection pool towards a single database.

org.neo4j.driver.config.max-transaction-retry-time

30s

Specify the maximum time transactions are allowed to retry.

org.neo4j.driver.config.server-address-resolver-class

Specify a custom server address resolver used by the routing driver to resolve the initial address used to create the driver.

org.neo4j.driver.config.trust-settings.cert-file

The file of the certificate to use.

org.neo4j.driver.config.trust-settings.hostname-verification-enabled

false

Flag, if hostname verification is used.

org.neo4j.driver.config.trust-settings.strategy

Configures the strategy to use use.

org.neo4j.driver.uri

The uri this driver should connect to. The driver supports bolt, bolt+routing or neo4j as schemes. The default URI is ‘bolt://localhost:7687’.

org.neo4j.driver.pool.metrics-enabled

false

Set this to true, so that the driver collects metrics, which can be exported to Micrometer.

Examples

We provide several examples how to use this starter. The reactive demo can only be used with Neo4j version 4.

Each example comes with a dedicated readme, that guides you through it.

The examples use the “Movie” data set, that you can install into your instance by going to the Neo4j Browser. Enter the command :play movies and follow the instructions.

The examples expect an instance with the username neo4j and the password secret.

All examples use Maven, however they work completely the same with Gradle.

Also, all examples follow Spring Boot conventions, especially: Use the dependency management and starters, don’t provide dependencies for things that are available as a starter. Use version properties for overwriting any managed version instead of an explicit version.

The examples all have the default main application class, that looks like this:

A standard Spring Boot main application class
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SimpleApplication {

	public static void main(String[] args) {
		SpringApplication.run(SimpleApplication.class, args);
	}
}
If you are a Visual Studio Code user, you’ll be happy to see that most of the examples include support for VS Code Remote Development. Please follow the instructions at the link above for setting up your Visual Studio Code environment. Once setup, you can open the example of your choice inside a VS Code container. The running example can be accessed from the outside as shown above without any further actions.

Web example

This example shows the usage of the Neo4j Java driver in a standard Spring Web-MVC application in an imperative (blocking) way.

Reactive web example

This example uses the neo4j:// protocol, which by defaults uses routing. Apart from that, the configuration is the same as with the simple example.

The driver is however used as a source for a reactive Neo4j session, which in turn produces results for a reactive Spring Rest Controller:

DisplayMoviesController.java
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import org.neo4j.driver.Driver;
import org.neo4j.driver.reactive.RxSession;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DisplayMoviesController {

	private final Driver driver;

	public DisplayMoviesController(Driver driver) {
		this.driver = driver;
	}

	@GetMapping(path = "/movies", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
	public Flux<String> getMovieTitles() {

		return Flux.usingWhen(
			Mono.fromSupplier(() -> driver.rxSession()),
			s -> Flux.from(s.run("MATCH (m:Movie) RETURN m ORDER BY m.name ASC").records()),
			RxSession::close
		).map(r -> r.get("m").asNode().get("title").asString());
	}
}

Testing against the Neo4j harness

First of all, you have to include the test harness in your dependencies. Pick either community edition or enterprise edition.

Here’s the community edition:

pom.xml
<dependency>
	<groupId>org.neo4j.test</groupId>
	<artifactId>neo4j-harness</artifactId>
	<version>${neo4j.version}</version>
	<scope>test</scope>
</dependency>

That brings a ton of dependencies. The advantage of it: It starts very fast. If you don’t want to have the dependencies and can live with a slower start, we recommend Testcontainers.

Starting up the Neo4j harness

There many different options. Here’s a simple JUnit 5 variant:

MoviesServiceTest.java
class MoviesServiceTest {

    private static ServerControls embeddedDatabaseServer;

    @BeforeAll
    static void initializeNeo4j() {
        embeddedDatabaseServer = TestServerBuilders
            .newInProcessBuilder()
            .newServer();
    }

    @AfterAll
    static void closeNeo4j() {
        embeddedDatabaseServer.close();
    }
}

Option a: Make Spring Boot aware of the URL of the embedded server

In either case, the real issue you have to solve during testing is: How to make Spring Boot aware that it should use different configuration properties?

We recommend using a custom org.springframework.context.ApplicationContextInitializer on a @SpringBootTest like this:

MoviesServiceTest.java
@SpringBootTest
@ContextConfiguration(initializers = { MoviesServiceTest.Initializer.class })
class MoviesServiceTest {

    private static ServerControls embeddedDatabaseServer;

    static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {

            TestPropertyValues.of(
                "org.neo4j.driver.uri=" + embeddedDatabaseServer.boltURI().toString(),
                "org.neo4j.driver.authentication.password="
            ).applyTo(configurableApplicationContext.getEnvironment());
        }
    }
}

Option b: Add your own driver bean to the context

We have this as MoviesServiceAltTest. While the configuration seems less complex, it changes more than just the url: Having a driver bean of your own in the context, disables the starter. That is of course ok, but you might end up with a very different configuration in test than in production. For example, you’ll notice that in MoviesServiceAltTest, the driver does not use Slf4j logging, but it’s own default.

Option a only adds properties with higher values onto the default ones. So, if you have configured more options of the driver in your application.properties or else, they still get applied. That is not the case for you own Driver bean.

Collecting metrics

This refers only to Driver metrics, not to the Neo4j server metrics.

neo4j-java-driver-spring-boot-starter comes with support for Micrometer metrics out of the box. It detects Micrometer on the classpath and binds the metrics of all instances of ` org.neo4j.driver.Driver`, that have enabled their metrics, to a micrometer registry.

Add org.springframework.boot:spring-boot-starter-actuator to your Spring Boot application, to include Micrometer. To enable metrics for the driver instance provided by this starter, set org.neo4j.driver.config.metrics-enabled to true then.

You’ll find this in the Reactive web example. Spring Boot doesn’t expose the metrics endpoint over http by default, if you need this, your complete configuration looks like this:

application.properties
# Enable metrics for the driver instance provided by this starter
org.neo4j.driver.config.metrics-enabled=true

# Expose metrics in addition to info and health over http
management.endpoints.web.exposure.include=info,health,metrics

The metrics can be accessed like any other metrics by their name. The following shows a CURL request retrieving the amount of acquired connections:

curl localhost:8080/actuator/metrics/neo4j.driver.connections.acquired|jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   287  100   287    0     0  32773      0 --:--:-- --:--:-- --:--:-- 35875
{
  "name": "neo4j.driver.connections.acquired",
  "description": "The amount of connections that have been acquired.",
  "baseUnit": "connections",
  "measurements": [
    {
      "statistic": "COUNT",
      "value": 102
    }
  ],
  "availableTags": [
    {
      "tag": "poolId",
      "values": [
        "localhost:7687"
      ]
    },
    {
      "tag": "name",
      "values": [
        "driver"
      ]
    }
  ]
}

Dedicated routing driver

Usually, a Neo4j cluster should be identified by one logical neo4j:// URL. This can be a load balancer, a DNS resolver, anything that turns the URL into a clusters entry point. There are however edge cases in which this is not feasible and you might want to pass multiple, physical neo4j:// URLs to the driver.

We don’t offer a dedicated configuration flag for that. The solution here is to define your own Driver-bean, but you can reuse our Neo4jDriverProperties that saves you from manually reading configuration properties.

The configuration is stored in src/main/resources/application.properties:

Unresolved directive in https://raw.githubusercontent.com/neo4j/neo4j-java-driver-spring-boot-starter/master/examples/dedicated-routing-driver/README.adoc - include::src/main/resources/application.properties[tags=custom-config]

To use the custom URIs, add a configuration class like this:

Unresolved directive in https://raw.githubusercontent.com/neo4j/neo4j-java-driver-spring-boot-starter/master/examples/dedicated-routing-driver/README.adoc - include::src/main/java/org/neo4j/doc/driver/springframework/boot/dedicated_routing_driver/RoutingDriverConfiguration.java[tags=custom-config]
1 Map your custom property with @Value onto a list of Strings or URIs.
2 Let our machinery inject Neo4jDriverProperties, that include all of our properties
3 Use the convenience methods to create org.neo4j.driver.AuthToken and org.neo4j.driver.Driver as needed. :leveloffset: -1