spring-projects / spring-boot

Spring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.
https://spring.io/projects/spring-boot
Apache License 2.0
75.41k stars 40.75k forks source link

Modify MongoClientSettings while using auto configuration with mongodb #20195

Closed heyarny closed 4 years ago

heyarny commented 4 years ago

First off, I'm not using reactive driver. There are examples using a MongoClientSettingsBuilderCustomizer bean to access the settings builder for modifications. But they don't seem to work with synchronous drivers, which is very confusing, even though they share the same settings.

Right now I'm kinda forced to create my own MongoClient bean to inject custom settings which will break all auto configuration.

I'm trying to register default codec for pojos, because I need them for some special cases.


    @Bean
    public MongoClientSettingsBuilderCustomizer customizer() {
        return (builder) -> {
            CodecRegistry pojoCodecRegistry = CodecRegistries.fromRegistries(
                MongoClientSettings.getDefaultCodecRegistry(),
                CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build()));

            builder.codecRegistry(pojoCodecRegistry);
        };
    }

Would appreciate any workaround for this, if this is not supported yet.

wilkinsona commented 4 years ago

Thanks for the report.

Right now I'm kinda forced to create my own MongoClient bean to inject custom settings which will break all auto configuration.

You should be able to create your own MongoClientSettings bean. It will be consumed by MongoAutoConfiguration and used to create the auto-configured MongoClient. The only benefit of the builder customizer approach over this is that it allows customisations from multiple sources to be applied. That's useful on the reactive side where we have some Netty customizations to apply. There are no such customizations on the blocking side so the builder customizer isn't strictly necessary.

With that said, I can see how the current arrangement is confusing as there's nothing to indicate that the builder customizer only applies to the reactive driver. When the feature was first introduced in Spring Boot 2.0, the type that was customized, com.mongodb.async.client.MongoClientSettings.Builder, was specific to Mongo's reactive driver. This changed to com.mongodb.MongoClientSettings.Builder in Spring Boot 2.1 but we didn't take the opportunity to make the customization available with the blocking driver as well.

Even just in the interests of consistency, it is tempting to support the builder customizer with the blocking driver. Failing that, we should at least update its javadoc to make it clear that it's specific to the reactive driver.

@mp911de if you have an opinion here one way or the other, please let us know.

heyarny commented 4 years ago

@wilkinsona well, I'd expect auto configuration to make its best choices for the settings and give me the opportunity to make additional modifications. Serving a closed MongoClientSettings would probably mean I'd have to take care over the 'best choises' part, which I'd rather love to hand over to spring boot.

Edit: oh, and of course I'd have to take care of all the properties set via application as well.

wilkinsona commented 4 years ago

There's no MongoClientSettings bean by default so providing one won't result in you losing anything. If you provide one, a Builder is created from those settings, otherwise a plain Builder is created. Either way Spring Boot's configuration and properties are applied to the Builder before it's used to create the client.

Put another way, you only need to provide a MongoClient bean if you want to take complete control of the client's configuration. Creating a MongoClientSettings bean will allow you to fine-tune Boot's opinions.

If you'd like to see how this is implemented, please take a look at the source for MongoClientFactory which is used by MongoAutoConfiguration to create the MongoClient bean.

heyarny commented 4 years ago

@wilkinsona Ok, sounds fine to me. I'll give it a try then.

Thanks! Have a great weekend :)

heyarny commented 4 years ago

@wilkinsona are you sure this bean is used by non-reactive configuration as well? It doesn't seem to work and I can't find any indication within the spring boot source which shows me the MongoClientSettings bean usage for non-reative auto configuration.

heyarny commented 4 years ago

Ok, I found the problem and it is totally confusing, again.

It's MongoClientOptions which is being used as bean, not MongoClientSettings. MongoClientOptions is deprecated and should be replaced by MongoClientSettings or at least check for both and fallback to MongoClientOptions.

Hope this helps to fix this.

heyarny commented 4 years ago

@wilkinsona by the way. I just saw that part with 'best choises' coming across. The default MongoClientSettings/MongoClientOptions is prefilled with codecs which I'd like to extend instead of replacing them. So I don't really see a way to get and extend them. So this is exactly why getting access to the builder would solve this.

Thanks for your time.

wilkinsona commented 4 years ago

Sorry for the confusion. We’ve switched to MongoClientSettings in 2.3. It is, as you have noted, MongoClientOptions in earlier versions.

mp911de commented 4 years ago

The issue is rooted in the fact that MongoDB ships two drivers, the synchronous and the async/reactive one. Both had in version 3.x/1.x different approaches to configuration using different API.

With the MongoDB 4.x driver, the configuration was fully unified into MongoClientSettings. MongoDB Driver 3.7/Reactive MongoDB Driver 1.8 introduced already support for MongoClientSettings but back then, we were past the 2.0 release and didn't consider breaking existing code a good idea, especially that MongoClientOptions still existed. Such a change would silently not apply configuration which would be even more harmful.

heyarny commented 4 years ago

@mp911de Yes, I understand. Still would be nice to have access to the builder in future releases for both reactive/async and sync. As of now I'll have to find another way on how to extend the default settings.

scottfrederick commented 4 years ago

We have an issue for 2.3.0 (#20019) to bring the auto-configuration for the reactive/async and sync MongoDB into closer alignment, and to reduce the code duplication there, now that the MongoDB drivers provide similar configuration.

scottfrederick commented 4 years ago

Superseded by #19960 and #20019 for Spring Boot 2.3.0.

adelinor commented 4 years ago

Hi @wilkinsona ,

I find the question raised in this issue very pertinent. As this issue is resolved, the reference documentation could be updated to indicate how one can customize options while retaining the auto configuration behaviour. As the getting started guide focuses on the data persistence aspects, the section 4.12.2 of the reference guide seems to the correct location for these details.

After searching various javadocs, such customization seems to be possible as per below:

@Configuration
public class MongodbConfig {

    @Bean
    public MongoClientSettingsBuilderCustomizer mongoDBDefaultSettings() {
        return builder -> {
            builder.applyToSslSettings( blockBuilder -> {
                blockBuilder.enabled(true).invalidHostNameAllowed(true);
            });
        };
    }
}
wilkinsona commented 4 years ago

@adelinor Thanks for the suggestion. I've opened https://github.com/spring-projects/spring-boot/issues/21696.

agarcia-te commented 4 years ago

@wilkinsona would it be possible to also update https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Release-Notes#mongodb-client-customization ?

wilkinsona commented 4 years ago

@agarcia-te What sort of update do you have in mind? Unlike the reference documentation prior to #21696 being fixed, the release notes already mention the settings builder customizer.

agarcia-te commented 4 years ago

@wilkinsona It doesn't warn that it only applies for reactive though, it makes it sound like that's the recommended way to do it in general.

sundarvenkata-EBI commented 3 years ago

Second @agarcia-te here. I have also been bitten by the same issue and wasted hours debugging it.

wilkinsona commented 3 years ago

I've made some updates to the release notes. It's worth noting, though, that all currently supported versions of Spring Boot (2.3.x and later) apply settings builder customizers with both the reactive and imperative drivers (https://github.com/spring-projects/spring-boot/issues/20019). If you're being bitten by this now then I suspect you're using an unsupported version and would recommend upgrading at your earliest convenience.

sundarvenkata-EBI commented 3 years ago

Thanks @wilkinsona. Appreciate the update!