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

Provide a possibility to extend/override configuration properties binding process #42361

Open
dmitriytsokolov opened this issue Sep 18, 2024 · 7 comments
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged

Comments

@dmitriytsokolov
Copy link

dmitriytsokolov commented Sep 18, 2024

We faced an issue where a property source for 700+- objects (consists of 100+- fields) binds to java objects slowly: around 6 minutes. Our services rely on spring cloud hot refresh and because of slow binding users are struggling. We could optimize this process for our use case, but most of the binding classes are closed for extension.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Sep 18, 2024
@philwebb
Copy link
Member

There's not really enough information here for us to be able to take any action. Could you describe what optimizations you're trying to apply and what changes you'd need to do them?

A sample application that shows the issue would also be very helpful. Perhaps if we profile it there might be some general optimizations we can apply for everyone.

@philwebb philwebb added the status: waiting-for-feedback We need additional information before we can continue label Sep 19, 2024
@dmitriytsokolov
Copy link
Author

dmitriytsokolov commented Sep 19, 2024

I'm mostly interested in extending org.springframework.boot.context.properties.bind.Binder class, but almost all classes inside org.springframework.boot.context.properties.bind are package-private.

About optimisation. I'm not sure it would work generally, but the idea is the following:
I have an ConfigurationProperties class which first child field is a hashmap, so my yml files that are bond to ConfigProps looks the following way:

config-props-prefix:
  some-root-field-name:
    map-key-1:
      obj-field1-key: value1
      obj-field2-key: value2
      ...

And I have thousands of such files that are bond to the map. And I don't need a property config-props-prefix.some-root-field-name.${some-map-key}.obj-field1-key to be processed by binder multiple times, so I could cache the result and use it for binding process of other map entries. Does it make any sense to you?

I'm using spring boot 2.7.18, but I've tested on spring boot 3.2.7 and performance is the same.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 19, 2024
@wilkinsona
Copy link
Member

@dmitriytsokolov thanks for the additional details. Can you please share a sample application that uses Spring Boot 3.2.x or later that demonstrates what you've described above?

@wilkinsona wilkinsona added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Sep 19, 2024
@dmitriytsokolov
Copy link
Author

@wilkinsona sure. Should I just create an example with couple of config files, or with hundreds to emulate performance issues?

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 19, 2024
@wilkinsona
Copy link
Member

Thanks. Something that replicates the performance issue would be ideal. Perhaps you could use a script to generate a sufficient volume of synthetic test data?

@wilkinsona wilkinsona added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Sep 19, 2024
@dmitriytsokolov
Copy link
Author

dmitriytsokolov commented Sep 23, 2024

attaching example of spring app with 1000 configs that is started up for 40-50s locally. In my real app I have more fields and more spring placeholders, so app start time/hot refresh takes 5-6 minutes
demo_config_props.zip

One more thing: initially I though that I could cache results of resolved spring placeholders (because I have a lot of them) and get some performance benefits, so I've made the following change in Binder class locally:

	private <T> Object bindProperty(Bindable<T> target, Context context, ConfigurationProperty property) {
		context.setConfigurationProperty(property);
		Object original = property.getValue();
		Object fromCache = this.resolvedPlaceholdersCache.get(original);
		if (fromCache != null) {
			return fromCache;
		}
		Object result = this.placeholdersResolver.resolvePlaceholders(original);
		result = context.getConverter().convert(result, target);
		this.resolvedPlaceholdersCache.put(original, result);
		return result;
	}

but I've got approximately minus 20 seconds out of 5-6 minutes of binding time. It's not much, but still with the ability to override/extend some binding logic I could reduce it even more knowing some specifics of my serivce

Anyway, will be waiting for your input, thanks a lot

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 23, 2024
@dmitriytsokolov
Copy link
Author

The other option I'm thinking of:
As you see I have a simple hashmap on the root level. So if only a part of the binding beans were opened for extension, I could try rebinding config props partially manually (binding of each map's element asynchronously and build the map by myself). This should help, but of course I'm not sure about it. I'm going to install local version of spring with required updates and will try to implement this approach in my app. But I would appreciate your input on this idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: feedback-provided Feedback has been provided status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

No branches or pull requests

4 participants