Skip to content

Bad property binding performance while use binder with an un enumerable property source #45970

Closed as not planned
@tanruian

Description

@tanruian

Upgrade spring-boot to 3.5.0, an issue where a property source binds to java objects slowly, for deep nested collection (consists of 4 depth), around 1 minutes. Number of scans of property with exponential growth.
Because the ManagementContextAutoConfiguration automatically adds an un enumerable property source to the environment,resulting in the inability to confirm whether the property source contains bindable property, requiring guessing and traversing property one by one based on the index 0-12

Root cause is changes in 93113a4

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.boot.context.properties.bind.AbstractBindHandler;
import org.springframework.boot.context.properties.bind.BindContext;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.env.PropertySource;
import org.springframework.lang.NonNull;

import java.util.List;

@Slf4j
public class SpringBindIssue {

    public static void main(String[] args) {

        var propertySources = List.of(ConfigurationPropertySource.from(new PropertySource<>("xxxx") {
            @Override
            public Object getProperty(@NonNull String name) {
                if (name.equals("xxxx")) {
                    return "xxx";
                }
                return null;
            }
        }));

        AbstractBindHandler abstractBindHandler = new AbstractBindHandler() {

            @Override
            public <T> Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {
                log.info("Start bind [{}] [{}]", target.getType(), name);
                return super.onStart(name, target, context);
            }

        };
        new Binder(propertySources, null, new ApplicationConversionService(), null, abstractBindHandler).bind("", NestedObject1.class);
    }


    @Setter
    @Getter
    public static class NestedObject1 {

        @NestedConfigurationProperty
        private List<NestedObject2> children;

    }

    @Setter
    @Getter
    public static class NestedObject2 {

        @NestedConfigurationProperty
        private List<NestedObject3> children;

    }

    @Setter
    @Getter
    public static class NestedObject3 {

        @NestedConfigurationProperty
        private List<NestedObject4> children;

    }

    @Setter
    @Getter
    public static class NestedObject4 {

        @NestedConfigurationProperty
        private List<String> children;

    }


}
Start bind [SpringBindIssue$NestedObject1] []
Start bind [java.util.List<SpringBindIssue$NestedObject2>] [children]
Start bind [SpringBindIssue$NestedObject2] [children[0]]
Start bind [java.util.List<SpringBindIssue$NestedObject3>] [children[0].children]
Start bind [SpringBindIssue$NestedObject3] [children[0].children[0]]
Start bind [java.util.List<SpringBindIssue$NestedObject4>] [children[0].children[0].children]
Start bind [SpringBindIssue$NestedObject4] [children[0].children[0].children[0]]
Start bind [java.util.List<java.lang.String>] [children[0].children[0].children[0].children]
Start bind [java.lang.String] [children[0].children[0].children[0].children[0]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[1]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[2]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[3]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[4]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[5]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[6]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[7]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[8]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[9]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[10]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[11]]
Start bind [java.lang.String] [children[0].children[0].children[0].children[12]]
Start bind [SpringBindIssue$NestedObject4] [children[0].children[0].children[1]]
Start bind [java.util.List<java.lang.String>] [children[0].children[0].children[1].children]
Start bind [java.lang.String] [children[0].children[0].children[1].children[0]]
Start bind [java.lang.String] [children[0].children[0].children[1].children[1]]
...
...
...
...

Metadata

Metadata

Assignees

Labels

status: supersededAn issue that has been superseded by another

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions