AbstractRouting would be a way to do it, indeed. You can mix that approach with headers on the request to easily implement multi-tenancy.
The link provided in another post on Baeldung does indeed provide a solution using such construct.
Sharding and deploying a separate micro-service for each tenant, with a routing service in front, would be another one and I think it offers several benefits both from coding (no need for thread-locals or other similarly difficult construct) and maintenance perspective (you can take down your service for maintenance/customisation at tenant level), so it would be my solution of choice in your specific case, assuming that business requirements allow for it.
Still, again, the best solution depends on your specific case.
The easiest solution matching the title of the question - for readers that are not necessarily concerned with multi-tenancy - would be to create several dataSource instances in your Spring's @Configuration beans, put them in a Map<Integer, DataSource> and then return that Map<Integer, DataSource> object as a Bean. When you have to access them, you access the Map bean you created and then create your NamedParameterJdbcTemplate or similar resource passing the specific DataSource in the constructor.
Pseudo-code example:
@Configuration
class DataSourceConfig {
public final static int SPAIN = 2;
public final static int BRAZIL = 1;
@Bean
@Qualifier("dataSources")
public Map<Integer, DataSource> dataSources() {
Map<Integer, DataSource> ds = new HashMap<>();
ds.put(SPAIN, buildSpainDataSource());
ds.put(BRAZIL, buildBrazilDataSource());
return ds;
}
private DataSource buildSpainDataSource() {
...
}
private DataSource buildBrazilDataSource() {
...
}
}
@Service
class MyService {
@Autowired
@Qualifier("dataSources")
Map<Integer, DataSource> dataSources;
Map<String, Object> getObjectForCountry(int country) {
NamedParameterJdbcTemplate t = new NamedParameterJdbcTemplate(dataSources.get(country));
return t.queryForMap("select value from mytable", new HashMap<>());
}
}