Skip to content
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

Metrics and health do not include non-default candidate beans #43481

Closed
mdaepp opened this issue Dec 11, 2024 · 12 comments
Closed

Metrics and health do not include non-default candidate beans #43481

mdaepp opened this issue Dec 11, 2024 · 12 comments
Labels
type: bug A general bug
Milestone

Comments

@mdaepp
Copy link

mdaepp commented Dec 11, 2024

The documentation for Spring Boot 3.4 now recommends the @Qualifier("xyz") and @Bean(defaultCandidate = false) approach to define multiple DataSources: https://docs.spring.io/spring-boot/3.4/how-to/data-access.html#howto.data-access.configure-two-datasources

At first glance, this approach is neat because the first DataSource is set up by auto-configuration as if there were no second DataSource. However, the new approach has some probably unwanted side-effects that users should be made aware of.

With the previous approach (see https://docs.spring.io/spring-boot/3.3/how-to/data-access.html#howto.data-access.configure-two-datasources), the additional DataSources would still participate in other auto-configurations such as DataSourcePoolMetricsAutoConfiguration and DataSourceHealthContributorAutoConfiguration. That is no longer the case with the new approach, because an additional DataSource with defaultCandidate = false is neither present in Map<String, DataSource> nor is it available via ObjectProvider<DataSource>.

I leave it to the subject matter experts to decide what should be done:

  1. Update documentation to mention the limitations of the new approach
  2. Revert documentation to previous approach
  3. Fix other auto-configurations that apply to a "list" of DataSources of some sort (such as ObjectProvider<DataSource>)—not sure if that is even possible or a good idea for that matter
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Dec 11, 2024
@quaff
Copy link
Contributor

quaff commented Dec 11, 2024

Fix other auto-configurations that apply to a "list" of DataSources of some sort (such as ObjectProvider<DataSource>)

ObjectProvider<DataSource> filter out non-defaultCandidate beans, we could use beanFactory.getBeansOfType(DataSource.class) instead of injection of Map<String, DataSource>.

@quaff
Copy link
Contributor

quaff commented Dec 11, 2024

Fix other auto-configurations that apply to a "list" of DataSources of some sort (such as ObjectProvider<DataSource>)

ObjectProvider<DataSource> filter out non-defaultCandidate beans, we could use beanFactory.getBeansOfType(DataSource.class) instead of injection of Map<String, DataSource>.

I'd like to prepare an PR if the team accept this solution, see https://github.com/spring-projects/spring-boot/compare/main...quaff:patch-108?expand=1.

quaff added a commit to quaff/spring-boot that referenced this issue Dec 11, 2024
Before this commit, non default and autowire candidate DataSources are not applied.

Closes spring-projectsGH-43481
@philwebb
Copy link
Member

philwebb commented Dec 11, 2024

I'm not a fan of using the BeanFactory directly, but I can't immediately think of a better option. @jhoeller Any thoughts on the best way to inject something that will include non-defaultCandidate beans? Perhaps we need some new methods on ObjectProvider or a new annotation to signal intent?

@philwebb philwebb added the status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team label Dec 11, 2024
@quaff
Copy link
Contributor

quaff commented Dec 12, 2024

I'm not a fan of using the BeanFactory directly, but I can't immediately think of a better option. @jhoeller Any thoughts on the best way to inject something that will include non-defaultCandidate beans? Perhaps we need some new methods on ObjectProvider or a new annotation to signal intent?

I vote for new methods on ObjectProvider, It's not good to introduce new annotation, make things more complex hard to understand.

@jhoeller
Copy link

jhoeller commented Dec 16, 2024

The intent was for such general container lookups to happen via beanFactory.getBeansOfType(DataSource.class) indeed, if necessary. defaultCandidate=false restricts user injection without qualifiers, and if framework components declare user-style injection points with those semantics, they get the same restricted view.

We could introduce new methods on ObjectProvider but it would blur the line with the user's view, so I would only consider that if it was a common need in user components. If defaultCandidate=false has unwanted side effects in a scenario, it might be the wrong choice. That said, for framework facilities, it's just a matter of using the appropriate lookup mechanism. In framework components, I don't consider direct interaction with an injected BeanFactory reference as inferior to ObjectProvider interaction.

@philwebb philwebb added for: team-meeting An issue we'd like to discuss as a team to make progress status: on-hold We can't start working on this issue yet labels Dec 16, 2024
@philwebb
Copy link
Member

Holding to the new year as we consider options

@snicoll snicoll added status: blocked An issue that's blocked on an external project change and removed status: on-hold We can't start working on this issue yet for: team-meeting An issue we'd like to discuss as a team to make progress status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team labels Jan 7, 2025
@snicoll
Copy link
Member

snicoll commented Jan 7, 2025

This issue is now blocked by spring-projects/spring-framework#34203. If implemented we'd hopefully be able to restore the previous behavior with such beans.

@snicoll snicoll removed the status: blocked An issue that's blocked on an external project change label Feb 3, 2025
@quaff

This comment has been minimized.

quaff added a commit to quaff/spring-boot that referenced this issue Feb 6, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
Before this commit, non default and autowire candidate DataSources are not applied.

Closes spring-projectsGH-43481

Signed-off-by: Yanming Zhou <zhouyanming@gmail.com>
@wilkinsona

This comment has been minimized.

@wilkinsona wilkinsona changed the title Document limitations of new approach to configure multiple DataSources Metrics and health do not include non-default candidate beans Feb 12, 2025
@wilkinsona wilkinsona added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Feb 12, 2025
@wilkinsona wilkinsona modified the milestones: 3.4.x, 3.4.3 Feb 12, 2025
@mdaepp
Copy link
Author

mdaepp commented Feb 13, 2025

@wilkinsona Thanks for fixing this! I think you forgot to adapt HikariDataSourceMetricsConfiguration org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration. It is implemented slightly differently as it uses ObjectProvider<DataSource> dataSources. If I am not mistaken, ObjectProvider still doesn't see non-default candidates. As-is, MicrometerMetricsTrackerFactory will not be registered for DataSources with defaultCandidate=false.

quaff added a commit to quaff/spring-boot that referenced this issue Feb 13, 2025
@quaff
Copy link
Contributor

quaff commented Feb 13, 2025

@wilkinsona Thanks for fixing this! I think you forgot to adapt HikariDataSourceMetricsConfiguration org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration. It is implemented slightly differently as it uses ObjectProvider<DataSource> dataSources. If I am not mistaken, ObjectProvider still doesn't see non-default candidates. As-is, MicrometerMetricsTrackerFactory will not be registered for DataSources with defaultCandidate=false.

You are right, I'd like to create PR if @wilkinsona think https://github.com/spring-projects/spring-boot/compare/main...quaff:patch-108?expand=1 is correct fix.

quaff added a commit to quaff/spring-boot that referenced this issue Feb 13, 2025
@wilkinsona
Copy link
Member

Well spotted, @mdaepp. Thank you.

@quaff, that change to the main code looks good to me, thank you. On the testing side, rather than adding a new test, I'd change TwoHikariDataSourcesConfiguration to this:

	@Configuration(proxyBeanMethods = false)
	static class MultipleHikariDataSourcesConfiguration {

		@Bean
		DataSource standardDataSource() {
			return createHikariDataSource("standardDataSource");
		}

		@Bean(defaultCandidate = false)
		DataSource nonDefault() {
			return createHikariDataSource("nonDefault");
		}

		@Bean(autowireCandidate = false)
		DataSource nonAutowire() {
			return createHikariDataSource("nonAutowire");
		}

	}

And then adapt the tests that used TwoHikariDataSourcesConfiguration to use MultipleHikariDataSourcesConfiguration instead and expect both standardDataSource and nonDefault.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

7 participants