diff --git a/spring-core/src/jmh/java/org/springframework/core/env/CompositePropertySourceBenchmark.java b/spring-core/src/jmh/java/org/springframework/core/env/CompositePropertySourceBenchmark.java new file mode 100644 index 0000000000..73d3d18f52 --- /dev/null +++ b/spring-core/src/jmh/java/org/springframework/core/env/CompositePropertySourceBenchmark.java @@ -0,0 +1,79 @@ +/* + * Copyright 2002-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.core.env; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.RandomStringUtils; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * Benchmarks for {@link CompositePropertySource}. + * + * @author Yike Xiao + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 5, time = 2) +@Measurement(iterations = 5, time = 2) +public class CompositePropertySourceBenchmark { + + @Benchmark + public void getPropertyNames(BenchmarkState state, Blackhole blackhole) { + blackhole.consume(state.composite.getPropertyNames()); + } + + @State(Scope.Benchmark) + public static class BenchmarkState { + + static final Object VALUE = new Object(); + + CompositePropertySource composite; + + @Param({"2", "5", "10"}) + int numberOfPropertySource; + + @Param({"10", "100", "1000"}) + int numberOfPropertyNamesPerSource; + + @Setup(Level.Trial) + public void setUp() { + this.composite = new CompositePropertySource("benchmark"); + for (int i = 0; i < this.numberOfPropertySource; i++) { + Map map = new HashMap<>(this.numberOfPropertyNamesPerSource); + for (int j = 0; j < this.numberOfPropertyNamesPerSource; j++) { + map.put(RandomStringUtils.randomAlphanumeric(5, 50), VALUE); + } + PropertySource propertySource = new MapPropertySource("propertySource" + i, map); + this.composite.addPropertySource(propertySource); + } + } + } +} diff --git a/spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java b/spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java index 6224a95f33..efc59f67a9 100644 --- a/spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java +++ b/spring-core/src/main/java/org/springframework/core/env/CompositePropertySource.java @@ -78,15 +78,22 @@ public class CompositePropertySource extends EnumerablePropertySource { @Override public String[] getPropertyNames() { - Set names = new LinkedHashSet<>(); + List namesList = new ArrayList<>(this.propertySources.size()); + int total = 0; for (PropertySource propertySource : this.propertySources) { if (!(propertySource instanceof EnumerablePropertySource enumerablePropertySource)) { throw new IllegalStateException( "Failed to enumerate property names due to non-enumerable property source: " + propertySource); } - names.addAll(Arrays.asList(enumerablePropertySource.getPropertyNames())); + String[] names = enumerablePropertySource.getPropertyNames(); + namesList.add(names); + total += names.length; } - return StringUtils.toStringArray(names); + Set allNames = new LinkedHashSet<>(total); + for (String[] names : namesList) { + allNames.addAll(Arrays.asList(names)); + } + return StringUtils.toStringArray(allNames); }