0% found this document useful (0 votes)
7 views

Database Routing2

This document discusses Spring's AbstractRoutingDatasource, which allows dynamically determining the actual DataSource based on context. It describes defining an enum to represent context, a context holder class to store the current context thread-locally, a router that extends AbstractRoutingDatasource to look up the context and return the correct DataSource, and a configuration with mappings of contexts to DataSources. Using this allows keeping DataSource lookup logic out of data access code.

Uploaded by

mohan
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

Database Routing2

This document discusses Spring's AbstractRoutingDatasource, which allows dynamically determining the actual DataSource based on context. It describes defining an enum to represent context, a context holder class to store the current context thread-locally, a router that extends AbstractRoutingDatasource to look up the context and return the correct DataSource, and a configuration with mappings of contexts to DataSources. Using this allows keeping DataSource lookup logic out of data access code.

Uploaded by

mohan
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

A Guide to Spring AbstractRoutingDatasource https://www.baeldung.

com/spring-abstract-routing-data-source

A Guide to Spring AbstractRoutingDatasource

Generic Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:
>> CHECK OUT THE COURSE

1. Overview
In this quick article, we'll look at Spring's AbstractRoutingDatasource as a way of dynamically determining the actual DataSource based on the current context.

As a result, we'll see that we can keep DataSource lookup logic out of the data access code.

2. Maven Dependencies
Let's start by declaring spring-context, spring-jdbc, spring-test, and h2 as dependencies in the pom.xml:

1
<dependencies>
2
<dependency>
3
<groupId>org.springframework</groupId>
4
<artifactId>spring-context</artifactId>
5
<version>4.3.8.RELEASE</version>
6
</dependency>

7 <dependency>

8 <groupId>org.springframework</groupId>

9 <artifactId>spring-jdbc</artifactId>

10 <version>4.3.8.RELEASE</version>

11 </dependency>

12 <dependency>

13 <groupId>org.springframework</groupId>

14 <artifactId>spring-test</artifactId>

15 <version>4.3.8.RELEASE</version>

16 <scope>test</scope>

17 </dependency>

1 of 5 05/09/19, 3:59 PM
A Guide to Spring AbstractRoutingDatasource https://www.baeldung.com/spring-abstract-routing-data-source

18

19 <dependency>

20 <groupId>com.h2database</groupId>

<artifactId>h2</artifactId>
21
<version>1.4.195</version>
22
<scope>test</scope>
23
</dependency>
24
</dependencies>
25

26

The latest version of the dependencies can be found here.

3. Datasource Context
AbstractRoutingDatasource requires information to know which actual DataSource to route to. This information is typically referred to as a Context.

While the Context used with AbstractRoutingDatasource can be any Object, an enum is used for defining them. In our example, we'll use the notion of a ClientDatabase as our context with the following
implementation:

1 public enum ClientDatabase {

2 CLIENT_A, CLIENT_B

3}

Its worth noting that, in practice, the context can be whatever makes sense for the domain in question.

For example, another common use case involves using the notion of an Environment to define the context. In such a scenario, the context could be an enum containing PRODUCTION, DEVELOPMENT,
and TESTING.

4. Context Holder
The context holder implementation is a container that stores the current context as a ThreadLocal reference.

In addition to holding the reference, it should contain static methods for setting, getting, and clearing it. AbstractRoutingDatasource will query the ContextHolder for the Context and will then use the
context to look up the actual DataSource.

It's critically important to use ThreadLocal here so that the context is bound to the currently executing thread.

It's essential to take this approach so that behavior is reliable when data access logic spans multiple data sources and uses transactions:

1
public class ClientDatabaseContextHolder {
2
private static ThreadLocal<ClientDatabase> CONTEXT

2 of 5 05/09/19, 3:59 PM
A Guide to Spring AbstractRoutingDatasource https://www.baeldung.com/spring-abstract-routing-data-source

5 = new ThreadLocal<>();

6 public static void set(ClientDatabase clientDatabase) {

7 Assert.notNull(clientDatabase, "clientDatabase cannot be null");

8 CONTEXT.set(clientDatabase);

}
9
public static ClientDatabase getClientDatabase() {
10
return CONTEXT.get();
11
}
12
public static void clear() {
13
CONTEXT.remove();
14
}
15
}
16

17

18

5. Datasource Router
We define our ClientDataSourceRouter to extend the Spring AbstractRoutingDataSource. We implement the necessary determineCurrentLookupKey method to query our ClientDatabaseContextHolder and
return the appropriate key.

The AbstractRoutingDataSource implementation handles the rest of the work for us and transparently returns the appropriate DataSource:

1
public class ClientDataSourceRouter
2
extends AbstractRoutingDataSource {
3
@Override
4
protected Object determineCurrentLookupKey() {
5
return ClientDatabaseContextHolder.getClientDatabase();
6
}
7
}
8

6. Configuration

3 of 5 05/09/19, 3:59 PM
A Guide to Spring AbstractRoutingDatasource https://www.baeldung.com/spring-abstract-routing-data-source

We need a Map of contexts to DataSource objects to configure our AbstractRoutingDataSource. We can also specify a default DataSource to use if there is no context set.

The DataSources we use can come from anywhere but will typically be either created at runtime or looked up using JNDI:

3
@Configuration
4
public class RoutingTestConfiguration {
5
@Bean
6
public ClientService clientService() {
7
return new ClientService(new ClientDao(clientDatasource()));
8
}
9
@Bean
10
public DataSource clientDatasource() {
11
Map<Object, Object> targetDataSources = new HashMap<>();
12
DataSource clientADatasource = clientADatasource();
13
DataSource clientBDatasource = clientBDatasource();
14
targetDataSources.put(ClientDatabase.CLIENT_A,
15
clientADatasource);
16
targetDataSources.put(ClientDatabase.CLIENT_B,
17
clientBDatasource);
18
ClientDataSourceRouter clientRoutingDatasource
19
= new ClientDataSourceRouter();
20
clientRoutingDatasource.setTargetDataSources(targetDataSources);
21
clientRoutingDatasource.setDefaultTargetDataSource(clientADatasource);
22
return clientRoutingDatasource;

23
}

24 }

25

26

27

4 of 5 05/09/19, 3:59 PM
A Guide to Spring AbstractRoutingDatasource https://www.baeldung.com/spring-abstract-routing-data-source

7. Usage
When using our AbstractRoutingDataSource, we first set the context and then perform our operation. We make use of a service layer that takes the context as a parameter and sets it before delegating to data-
access code and clearing the context after the call.

As an alternative to manually clearing the context within a service method, the clearing logic can be handled by an AOP point cut.

It's important to remember that the context is thread bound especially if data access logic will be spanning multiple data sources and transactions:

3 public class ClientService {

4 private ClientDao clientDao;

5 public String getClientName(ClientDatabase clientDb) {

6 ClientDatabaseContextHolder.set(clientDb);

7 String clientName = this.clientDao.getClientName();

8 ClientDatabaseContextHolder.clear();

9 return clientName;

10 }

11 }

12

13

8. Conclusion
In this tutorial, we looked at the example how to use the Spring AbstractRoutingDataSource. We implemented a solution using the notion of a Client – where each client has its DataSource.

And, as always, examples can found over on GitHub.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:
>> CHECK OUT THE COURSE

5 of 5 05/09/19, 3:59 PM

You might also like