-
Notifications
You must be signed in to change notification settings - Fork 40.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide support for auto-configuring multiple beans #15732
Comments
We might also need |
With such a property design, I would like the current |
Please note that |
We should keep We should also ensure that whatever we come up with isn't just applicable to DataSources. #25369 raised the possibility of configuring multiple RabbitMQ connection factories and we need something that's consistent across all sorts of different data stores, message brokers, etc. |
Completely concur with that last point, I have just recently had the same requirement for kafka. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I think that's only useful right now for e.g. multi-tenant systems where you route on e.g. In the former case, if there is auto-configuration of multiple |
To be clear, I wasn't proposing that we'd always automatically create the |
I'm not sure there's any opinionated way to do that. You could tag each DS with a routing value in its properties, but you still need an implementation to determine what the selected value should be when creating a connection. |
Indeed. You'd need something that provides the logic for at least |
I've change the issue's title to reflect the fact that this should work for any type of bean and not just for data sources. Once we've figured out the general approach, we can then open additional issues as needed to tackle anything that's When we start working on this, #32194 contains some interesting ideas that we should evaluate and discuss with the Framework team. |
Hi! myapp.config:
# generic configuration
datasouce:
hikari:
minimum-idle: 2
maximum-pool-size: 10
idle-timeout: 30000
max-lifetime: 60000
liquibase:
change-log: classpath:db/changelog/db.changelog-master.xml
tenants:
- name: master
datasource:
url: ${DATABASE_URL}
username: ${DATABASE_USERNAME}
password: ${DATABASE_PASSWORD}
# other configs are inherited from the generic configuration
- name: client1
datasource:
url: ${DATABASE_URL_CLIENT1}
username: ${DATABASE_USERNAME}
password: ${DATABASE_PASSWORD}
# overrides the generic configuration
hikari:
minimum-idle: 4
maximum-pool-size: 10
idle-timeout: 30000
max-lifetime: 60000
liquibase:
change-log: classpath:db/changelog/db.changelog-client1.xml it supports both cases that u have mentioned for HikariConfig hikariConfig = customHikariConfig != null ? customHikariConfig : genericHikariConfig; Still figuring out how to apply liquibase migrations for all datasources, as for now spring boot doesn't support migration of a bean of type |
Please refer to my solution here spring-projects/spring-framework#21415 |
Hi @wilkinsona, what's the status of this topic? There are a lot of ideas and codesnips to support multiple beans, but all are declined or the discussion has stopped. For flyway we need multiple bean support for different schemas with the same or with different databases. The usecases are motivated by providing shared libs with migrations in classpath, which are fired against isolated environments. I have two different drafts:
Both designs are fully compatible with the current behaviour, but after reading the other issues (like #25369) I'am a bit disillusioned to finish the test and the documentation, just for it to get declined as well. What's the decision from the framework team with this design topic? Greetings, |
This is something that we'd like to support but we do not yet know how to do so. Some design work is required and, unfortunately, until that has happened, we're unlikely to be in a position to accept a contribution. Perhaps you could share your drafts in their current form by linking to your fork so that we can take what you're trying to do into consideration? |
@wilkinsona I know we already discussed the multitenancy datasource feature in #28812. But really, 3 years later, I do encourage the lead team to reassess providing such a feature. I think it is the most recurrent most complex feature we need to build over the near perfect Boot, and almost everyone have same needs (you even have a blog post about it https://spring.io/blog/2022/07/31/how-to-integrate-hibernates-multitenant-feature-with-spring-data-jpa-in-a-spring-boot-application). AbstractRoutingDataSource does not make it trivial to modify the list of datasources in runtime in a thread-safe way, nor has a built-in integration with Hibernate multitenancy gimmicks (so you have to deal with very low-level stuff for the L2 cache to work fine), it does not provide efficient initialization facilities (like async init if you have 2000 datasources, and the fact that the hibernate-recommended use_jdbc_metadata_defaults settings makes you having to manage the datasource map in order to provide the lenientFallback/defaultDatasource arbitrarily), it does not integrate with Flyway. And besides, integrating the determineCurrentLookupKey() with jwt resource-server oauth would be really easy. I don't think such arch would require a massive rework and it's certainly a killer feature. There's dozens of resources in internet trying to approach this need and a standard way would be amazing. The abstraction of the datsourceconfig source, and the one that deals with tenant mapping to datasource (schema,table,database) would be more time-consuming, but I think it's feasible |
Please consider the following approach to structure the properties: myapp.first-datasource.spring.datasource.name=FirstDS
myapp.first-datasource.spring.datasource.url=jdbc:postgresql://first:5432/first
myapp.first-datasource.spring.datasource.username=first
myapp.first-datasource.spring.datasource.password=first
myapp.second-datasource.spring.datasource.name=SecondDS
myapp.second-datasource.spring.datasource.url=jdbc:mysql://second:5432/second
myapp.second-datasource.spring.datasource.username=second
myapp.second-datasource.spring.datasource.password=second And then a developer defines their own @ConfigurationProperties(prefix="myapp")
public class MyAppProperties {
private DataSourceProperties firstDatasource;
private DataSourceProperties secondDatasource;
// getters + setters
} Spring Boot should notice that there are Please find more info in #42179 |
Hello, is this issue still being discussed ? I would love to have some directions at least on the API/property level so i can implement my own/preview that will be forward compatible |
It's used for configuring multiple beans (spring-projects#15732), we could extract common or use primary properties as parent now. Take `org.springframework.boot.autoconfigure.data.redis.RedisProperties` for example, given: ``` # primary spring.data.redis: host: 127.0.0.1 port: 6379 # additional additional.data.redis: port: 6380 ``` Then effective properties: ``` additional.data.redis: host: 127.0.0.1 port: 6380 ``` should be bound to `additionalRedisProperties`: ```java @bean(autowireCandidate = false) // do not back off autoconfigured one @ConfigurationProperties(prefix = "additional.data.redis", inheritedPrefix = "spring.data.redis") RedisProperties additionalRedisProperties() { return new RedisProperties(); } ```
It's used for configuring multiple beans (spring-projects#15732), we could extract common or use primary properties as parent now. Take `org.springframework.boot.autoconfigure.data.redis.RedisProperties` for example, given: ``` # primary spring.data.redis: host: 127.0.0.1 port: 6379 # additional additional.data.redis: port: 6380 ``` Then effective properties: ``` additional.data.redis: host: 127.0.0.1 port: 6380 ``` should be bound to `additionalRedisProperties`: ```java @bean(autowireCandidate = false) // do not back off autoconfigured one @ConfigurationProperties(prefix = "additional.data.redis", inheritedPrefix = "spring.data.redis") RedisProperties additionalRedisProperties() { return new RedisProperties(); } ```
I think #42605 is a better alternative. |
It's used for configuring multiple beans (spring-projects#15732), we could extract common or use primary properties as parent now. Take `org.springframework.boot.autoconfigure.data.redis.RedisProperties` for example, given: ``` # primary spring.data.redis: host: 127.0.0.1 port: 6379 # additional additional.data.redis: port: 6380 ``` Then effective properties: ``` additional.data.redis: host: 127.0.0.1 port: 6380 ``` should be bound to `additionalRedisProperties`: ```java @bean(autowireCandidate = false) // do not back off autoconfigured one @ConfigurationProperties(prefix = "additional.data.redis", inheritedPrefix = "spring.data.redis") RedisProperties additionalRedisProperties() { return new RedisProperties(); } ```
It's used for configuring multiple beans (spring-projects#15732), we could extract common or use primary properties as parent now. Take `org.springframework.boot.autoconfigure.data.redis.RedisProperties` for example, given: ``` # primary spring.data.redis: host: 127.0.0.1 port: 6379 # additional additional.data.redis: port: 6380 ``` Then effective properties: ``` additional.data.redis: host: 127.0.0.1 port: 6380 ``` should be bound to `additionalRedisProperties`: ```java @bean(autowireCandidate = false) // do not back off autoconfigured one @ConfigurationProperties(prefix = "additional.data.redis", inheritedPrefix = "spring.data.redis") RedisProperties additionalRedisProperties() { return new RedisProperties(); } ```
Here is my prototype to support configuring multiple Take
Then effective properties:
should be bound to @Bean(autowireCandidate = false) // do not back off autoconfigured one
@ConfigurationProperties(prefix = "additional.data.redis", inheritedPrefix = "spring.data.redis")
RedisProperties additionalRedisProperties() {
return new RedisProperties();
} Please note |
This should be already known as per #31337 (comment), but I want to mention this is relevant for the work on auto-config for HTTP interface clients. There is some relevant work in httpexchange-spring-boot-starter where you can see a configuration model for multiple clients along with a more extensive example. Note there are common properties at the top, and more specific per client property sets below (under channels). However this ends up looking, the concept of common defaults seems useful. |
@wilkinsona I previously designed a Redis multi-datasource Spring Boot Starter, which may not be perfect. Recently, during my free time, I decided to open-source it. Here’s the link: https://github.com/ChildrenGreens/multi-source-spring-boot-starter. |
Auto-configuration of a single DataSource works well for the vast majority of users, but when a subsequent DataSource is required things get harder (see #7652 for one example) as all of the data sources then need to be manually configured. We'd like to make things easier by providing support for auto-configuring multiple DataSources. In terms of properties, this could look something like this:
Some more design work is needed, but
primary
could be used as a "special" name that results in the auto-configured bean being marked as@Primary
. We'd also need similar functionality for components that consume aDataSource
such as JPA, transaction management, Flyway and Liquibase.The text was updated successfully, but these errors were encountered: