Browse Source
This commit rewrites the remaining "fastEnough" performance tests into proper JMH benchmarks. See gh-24830pull/25823/head
22 changed files with 752 additions and 1047 deletions
@ -0,0 +1,101 @@
@@ -0,0 +1,101 @@
|
||||
/* |
||||
* Copyright 2002-2020 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.beans; |
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark; |
||||
import org.openjdk.jmh.annotations.BenchmarkMode; |
||||
import org.openjdk.jmh.annotations.Mode; |
||||
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.springframework.beans.propertyeditors.CustomNumberEditor; |
||||
import org.springframework.beans.propertyeditors.StringTrimmerEditor; |
||||
|
||||
/** |
||||
* Benchmark for {@link AbstractPropertyAccessor} use on beans. |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@BenchmarkMode(Mode.Throughput) |
||||
public class AbstractPropertyAccessorBenchmark { |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class BenchmarkState { |
||||
|
||||
@Param({"DirectFieldAccessor", "BeanWrapper"}) |
||||
public String accessor; |
||||
|
||||
@Param({"none", "stringTrimmer", "numberOnPath", "numberOnNestedPath", "numberOnType"}) |
||||
public String customEditor; |
||||
|
||||
public int[] input; |
||||
|
||||
public PrimitiveArrayBean target; |
||||
|
||||
public AbstractPropertyAccessor propertyAccessor; |
||||
|
||||
@Setup |
||||
public void setup() { |
||||
this.target = new PrimitiveArrayBean(); |
||||
this.input = new int[1024]; |
||||
if (this.accessor.equals("DirectFieldAccessor")) { |
||||
this.propertyAccessor = new DirectFieldAccessor(this.target); |
||||
} |
||||
else { |
||||
this.propertyAccessor = new BeanWrapperImpl(this.target); |
||||
} |
||||
switch (this.customEditor) { |
||||
case "stringTrimmer": |
||||
this.propertyAccessor.registerCustomEditor(String.class, new StringTrimmerEditor(false)); |
||||
break; |
||||
case "numberOnPath": |
||||
this.propertyAccessor.registerCustomEditor(int.class, "array.somePath", new CustomNumberEditor(Integer.class, false)); |
||||
break; |
||||
case "numberOnNestedPath": |
||||
this.propertyAccessor.registerCustomEditor(int.class, "array[0].somePath", new CustomNumberEditor(Integer.class, false)); |
||||
break; |
||||
case "numberOnType": |
||||
this.propertyAccessor.registerCustomEditor(int.class, new CustomNumberEditor(Integer.class, false)); |
||||
break; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
@Benchmark |
||||
public PrimitiveArrayBean setPropertyValue(BenchmarkState state) { |
||||
state.propertyAccessor.setPropertyValue("array", state.input); |
||||
return state.target; |
||||
} |
||||
|
||||
@SuppressWarnings("unused") |
||||
private static class PrimitiveArrayBean { |
||||
|
||||
private int[] array; |
||||
|
||||
public int[] getArray() { |
||||
return this.array; |
||||
} |
||||
|
||||
public void setArray(int[] array) { |
||||
this.array = array; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
/* |
||||
* Copyright 2002-2020 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.beans.factory; |
||||
|
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Date; |
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark; |
||||
import org.openjdk.jmh.annotations.BenchmarkMode; |
||||
import org.openjdk.jmh.annotations.Mode; |
||||
import org.openjdk.jmh.annotations.Scope; |
||||
import org.openjdk.jmh.annotations.Setup; |
||||
import org.openjdk.jmh.annotations.State; |
||||
import org.openjdk.jmh.infra.Blackhole; |
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; |
||||
import org.springframework.beans.propertyeditors.CustomDateEditor; |
||||
|
||||
import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; |
||||
|
||||
/** |
||||
* Benchmark for creating prototype beans in a concurrent fashion. |
||||
* This benchmark requires to customize the number of worker threads {@code -t <int>} on the |
||||
* CLI when running this particular benchmark to leverage concurrency. |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@BenchmarkMode(Mode.Throughput) |
||||
public class ConcurrentBeanFactoryBenchmark { |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class BenchmarkState { |
||||
|
||||
public DefaultListableBeanFactory factory; |
||||
|
||||
@Setup |
||||
public void setup() { |
||||
this.factory = new DefaultListableBeanFactory(); |
||||
new XmlBeanDefinitionReader(this.factory).loadBeanDefinitions( |
||||
qualifiedResource(ConcurrentBeanFactoryBenchmark.class, "context.xml")); |
||||
|
||||
this.factory.addPropertyEditorRegistrar( |
||||
registry -> registry.registerCustomEditor(Date.class, |
||||
new CustomDateEditor(new SimpleDateFormat("yyyy/MM/dd"), false))); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Benchmark |
||||
public void concurrentBeanCreation(BenchmarkState state, Blackhole bh) { |
||||
bh.consume(state.factory.getBean("bean1")); |
||||
bh.consume(state.factory.getBean("bean2")); |
||||
} |
||||
|
||||
|
||||
public static class ConcurrentBean { |
||||
|
||||
private Date date; |
||||
|
||||
public Date getDate() { |
||||
return this.date; |
||||
} |
||||
|
||||
public void setDate(Date date) { |
||||
this.date = date; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,142 @@
@@ -0,0 +1,142 @@
|
||||
/* |
||||
* Copyright 2002-2020 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.beans.factory; |
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark; |
||||
import org.openjdk.jmh.annotations.BenchmarkMode; |
||||
import org.openjdk.jmh.annotations.Mode; |
||||
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.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.config.RuntimeBeanReference; |
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||
import org.springframework.beans.testfixture.beans.LifecycleBean; |
||||
import org.springframework.beans.testfixture.beans.TestBean; |
||||
|
||||
/** |
||||
* Benchmark for retrieving various bean types from the {@link DefaultListableBeanFactory}. |
||||
* |
||||
* @author Brian Clozel |
||||
*/ |
||||
@BenchmarkMode(Mode.Throughput) |
||||
public class DefaultListableBeanFactoryBenchmark { |
||||
|
||||
public static class Shared { |
||||
public DefaultListableBeanFactory beanFactory; |
||||
} |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class PrototypeCreationState extends Shared { |
||||
|
||||
@Param({"simple", "dependencyCheck", "constructor", "constructorArgument", "properties", "resolvedProperties"}) |
||||
public String mode; |
||||
|
||||
@Setup |
||||
public void setup() { |
||||
this.beanFactory = new DefaultListableBeanFactory(); |
||||
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); |
||||
|
||||
switch (this.mode) { |
||||
case "simple": |
||||
break; |
||||
case "dependencyCheck": |
||||
rbd = new RootBeanDefinition(LifecycleBean.class); |
||||
rbd.setDependencyCheck(RootBeanDefinition.DEPENDENCY_CHECK_OBJECTS); |
||||
this.beanFactory.addBeanPostProcessor(new LifecycleBean.PostProcessor()); |
||||
break; |
||||
case "constructor": |
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue("juergen"); |
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue("99"); |
||||
break; |
||||
case "constructorArgument": |
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference("spouse")); |
||||
this.beanFactory.registerBeanDefinition("test", rbd); |
||||
this.beanFactory.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); |
||||
break; |
||||
case "properties": |
||||
rbd.getPropertyValues().add("name", "juergen"); |
||||
rbd.getPropertyValues().add("age", "99"); |
||||
break; |
||||
case "resolvedProperties": |
||||
rbd.getPropertyValues().add("spouse", new RuntimeBeanReference("spouse")); |
||||
this.beanFactory.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); |
||||
break; |
||||
} |
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); |
||||
this.beanFactory.registerBeanDefinition("test", rbd); |
||||
this.beanFactory.freezeConfiguration(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Benchmark |
||||
public Object prototypeCreation(PrototypeCreationState state) { |
||||
return state.beanFactory.getBean("test"); |
||||
} |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class SingletonLookupState extends Shared { |
||||
|
||||
@Setup |
||||
public void setup() { |
||||
this.beanFactory = new DefaultListableBeanFactory(); |
||||
this.beanFactory.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class)); |
||||
this.beanFactory.freezeConfiguration(); |
||||
} |
||||
} |
||||
|
||||
@Benchmark |
||||
public Object singletLookup(SingletonLookupState state) { |
||||
return state.beanFactory.getBean("test"); |
||||
} |
||||
|
||||
@Benchmark |
||||
public Object singletLookupByType(SingletonLookupState state) { |
||||
return state.beanFactory.getBean(TestBean.class); |
||||
} |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class SingletonLookupManyBeansState extends Shared { |
||||
|
||||
@Setup |
||||
public void setup() { |
||||
this.beanFactory = new DefaultListableBeanFactory(); |
||||
this.beanFactory.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class)); |
||||
for (int i = 0; i < 1000; i++) { |
||||
this.beanFactory.registerBeanDefinition("a" + i, new RootBeanDefinition(A.class)); |
||||
} |
||||
this.beanFactory.freezeConfiguration(); |
||||
} |
||||
} |
||||
|
||||
// See SPR-6870
|
||||
@Benchmark |
||||
public Object singletLookupByTypeManyBeans(SingletonLookupState state) { |
||||
return state.beanFactory.getBean(B.class); |
||||
} |
||||
|
||||
static class A { |
||||
} |
||||
|
||||
static class B { |
||||
} |
||||
|
||||
} |
||||
@ -1,168 +0,0 @@
@@ -1,168 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2019 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.beans.factory; |
||||
|
||||
import java.text.DateFormat; |
||||
import java.text.ParseException; |
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Collections; |
||||
import java.util.Date; |
||||
import java.util.HashSet; |
||||
import java.util.Iterator; |
||||
import java.util.Set; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; |
||||
import org.springframework.beans.propertyeditors.CustomDateEditor; |
||||
import org.springframework.core.testfixture.EnabledForTestGroups; |
||||
import org.springframework.core.testfixture.TestGroup; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.springframework.core.testfixture.io.ResourceTestUtils.qualifiedResource; |
||||
|
||||
/** |
||||
* @author Guillaume Poirier |
||||
* @author Juergen Hoeller |
||||
* @author Chris Beams |
||||
* @since 10.03.2004 |
||||
*/ |
||||
@EnabledForTestGroups(TestGroup.PERFORMANCE) |
||||
public class ConcurrentBeanFactoryTests { |
||||
|
||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd"); |
||||
|
||||
private static final Date DATE_1, DATE_2; |
||||
|
||||
static { |
||||
try { |
||||
DATE_1 = DATE_FORMAT.parse("2004/08/08"); |
||||
DATE_2 = DATE_FORMAT.parse("2000/02/02"); |
||||
} |
||||
catch (ParseException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ConcurrentBeanFactoryTests.class); |
||||
|
||||
private BeanFactory factory; |
||||
|
||||
private final Set<TestRun> set = Collections.synchronizedSet(new HashSet<>()); |
||||
|
||||
private Throwable ex; |
||||
|
||||
|
||||
@BeforeEach |
||||
public void setup() throws Exception { |
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); |
||||
new XmlBeanDefinitionReader(factory).loadBeanDefinitions( |
||||
qualifiedResource(ConcurrentBeanFactoryTests.class, "context.xml")); |
||||
|
||||
factory.addPropertyEditorRegistrar( |
||||
registry -> registry.registerCustomEditor(Date.class, |
||||
new CustomDateEditor((DateFormat) DATE_FORMAT.clone(), false))); |
||||
|
||||
this.factory = factory; |
||||
} |
||||
|
||||
|
||||
@Test |
||||
public void testSingleThread() { |
||||
for (int i = 0; i < 100; i++) { |
||||
performTest(); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void testConcurrent() { |
||||
for (int i = 0; i < 100; i++) { |
||||
TestRun run = new TestRun(); |
||||
run.setDaemon(true); |
||||
set.add(run); |
||||
} |
||||
for (Iterator<TestRun> it = new HashSet<>(set).iterator(); it.hasNext();) { |
||||
TestRun run = it.next(); |
||||
run.start(); |
||||
} |
||||
logger.info("Thread creation over, " + set.size() + " still active."); |
||||
synchronized (set) { |
||||
while (!set.isEmpty() && ex == null) { |
||||
try { |
||||
set.wait(); |
||||
} |
||||
catch (InterruptedException e) { |
||||
logger.info(e.toString()); |
||||
} |
||||
logger.info(set.size() + " threads still active."); |
||||
} |
||||
} |
||||
if (ex != null) { |
||||
throw new AssertionError("Unexpected exception", ex); |
||||
} |
||||
} |
||||
|
||||
private void performTest() { |
||||
ConcurrentBean b1 = (ConcurrentBean) factory.getBean("bean1"); |
||||
ConcurrentBean b2 = (ConcurrentBean) factory.getBean("bean2"); |
||||
|
||||
assertThat(b1.getDate()).isEqualTo(DATE_1); |
||||
assertThat(b2.getDate()).isEqualTo(DATE_2); |
||||
} |
||||
|
||||
|
||||
private class TestRun extends Thread { |
||||
|
||||
@Override |
||||
public void run() { |
||||
try { |
||||
for (int i = 0; i < 10000; i++) { |
||||
performTest(); |
||||
} |
||||
} |
||||
catch (Throwable e) { |
||||
ex = e; |
||||
} |
||||
finally { |
||||
synchronized (set) { |
||||
set.remove(this); |
||||
set.notifyAll(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
public static class ConcurrentBean { |
||||
|
||||
private Date date; |
||||
|
||||
public Date getDate() { |
||||
return date; |
||||
} |
||||
|
||||
public void setDate(Date date) { |
||||
this.date = date; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,105 @@
@@ -0,0 +1,105 @@
|
||||
/* |
||||
* Copyright 2002-2020 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.context.annotation; |
||||
|
||||
import javax.annotation.Resource; |
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark; |
||||
import org.openjdk.jmh.annotations.BenchmarkMode; |
||||
import org.openjdk.jmh.annotations.Mode; |
||||
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.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.config.RuntimeBeanReference; |
||||
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||
import org.springframework.beans.testfixture.beans.ITestBean; |
||||
import org.springframework.beans.testfixture.beans.TestBean; |
||||
import org.springframework.context.support.GenericApplicationContext; |
||||
|
||||
/** |
||||
* Benchmark for bean annotation processing with various annotations. |
||||
* @author Brian Clozel |
||||
*/ |
||||
@BenchmarkMode(Mode.Throughput) |
||||
public class AnnotationProcessorBenchmark { |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class BenchmarkState { |
||||
|
||||
public GenericApplicationContext context; |
||||
|
||||
@Param({"ResourceAnnotatedTestBean", "AutowiredAnnotatedTestBean"}) |
||||
public String testBeanClass; |
||||
|
||||
@Param({"true", "false"}) |
||||
public boolean overridden; |
||||
|
||||
@Setup |
||||
public void setup() { |
||||
RootBeanDefinition rbd; |
||||
this.context = new GenericApplicationContext(); |
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.context); |
||||
this.context.refresh(); |
||||
if (this.testBeanClass.equals("ResourceAnnotatedTestBean")) { |
||||
rbd = new RootBeanDefinition(ResourceAnnotatedTestBean.class); |
||||
} |
||||
else { |
||||
rbd = new RootBeanDefinition(AutowiredAnnotatedTestBean.class); |
||||
} |
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); |
||||
if (this.overridden) { |
||||
rbd.getPropertyValues().add("spouse", new RuntimeBeanReference("spouse")); |
||||
} |
||||
this.context.registerBeanDefinition("test", rbd); |
||||
this.context.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); |
||||
} |
||||
} |
||||
|
||||
@Benchmark |
||||
public ITestBean prototypeCreation(BenchmarkState state) { |
||||
TestBean tb = state.context.getBean("test", TestBean.class); |
||||
return tb.getSpouse(); |
||||
} |
||||
|
||||
|
||||
private static class ResourceAnnotatedTestBean extends org.springframework.beans.testfixture.beans.TestBean { |
||||
|
||||
@Override |
||||
@Resource |
||||
@SuppressWarnings("deprecation") |
||||
@org.springframework.beans.factory.annotation.Required |
||||
public void setSpouse(ITestBean spouse) { |
||||
super.setSpouse(spouse); |
||||
} |
||||
} |
||||
|
||||
private static class AutowiredAnnotatedTestBean extends TestBean { |
||||
|
||||
@Override |
||||
@Autowired |
||||
@SuppressWarnings("deprecation") |
||||
@org.springframework.beans.factory.annotation.Required |
||||
public void setSpouse(ITestBean spouse) { |
||||
super.setSpouse(spouse); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,71 @@
@@ -0,0 +1,71 @@
|
||||
/* |
||||
* Copyright 2002-2020 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.context.expression; |
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark; |
||||
import org.openjdk.jmh.annotations.BenchmarkMode; |
||||
import org.openjdk.jmh.annotations.Mode; |
||||
import org.openjdk.jmh.annotations.Scope; |
||||
import org.openjdk.jmh.annotations.Setup; |
||||
import org.openjdk.jmh.annotations.State; |
||||
import org.openjdk.jmh.annotations.TearDown; |
||||
import org.openjdk.jmh.infra.Blackhole; |
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||
import org.springframework.beans.testfixture.beans.TestBean; |
||||
import org.springframework.context.support.GenericApplicationContext; |
||||
|
||||
/** |
||||
* Benchmark for application context expressions resolution during prototype bean creation. |
||||
* @author Brian Clozel |
||||
*/ |
||||
@BenchmarkMode(Mode.Throughput) |
||||
public class ApplicationContextExpressionBenchmark { |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class BenchmarkState { |
||||
|
||||
public GenericApplicationContext context; |
||||
|
||||
@Setup |
||||
public void setup() { |
||||
System.getProperties().put("name", "juergen"); |
||||
System.getProperties().put("country", "UK"); |
||||
this.context = new GenericApplicationContext(); |
||||
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class); |
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); |
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue("#{systemProperties.name}"); |
||||
rbd.getPropertyValues().add("country", "#{systemProperties.country}"); |
||||
this.context.registerBeanDefinition("test", rbd); |
||||
this.context.refresh(); |
||||
} |
||||
|
||||
@TearDown |
||||
public void teardown() { |
||||
System.getProperties().remove("country"); |
||||
System.getProperties().remove("name"); |
||||
} |
||||
} |
||||
|
||||
@Benchmark |
||||
public void prototypeCreationWithSystemProperties(BenchmarkState state, Blackhole bh) { |
||||
TestBean tb = (TestBean) state.context.getBean("test"); |
||||
bh.consume(tb.getName()); |
||||
bh.consume(tb.getCountry()); |
||||
} |
||||
} |
||||
@ -1,161 +0,0 @@
@@ -1,161 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2019 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.context.annotation; |
||||
|
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.TimeUnit; |
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
|
||||
import javax.annotation.Resource; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.awaitility.Awaitility; |
||||
import org.junit.jupiter.api.BeforeAll; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
||||
import org.springframework.beans.factory.config.BeanDefinition; |
||||
import org.springframework.beans.factory.config.RuntimeBeanReference; |
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||
import org.springframework.beans.testfixture.beans.ITestBean; |
||||
import org.springframework.beans.testfixture.beans.TestBean; |
||||
import org.springframework.context.support.GenericApplicationContext; |
||||
import org.springframework.core.testfixture.Assume; |
||||
import org.springframework.core.testfixture.EnabledForTestGroups; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.springframework.core.testfixture.TestGroup.PERFORMANCE; |
||||
|
||||
/** |
||||
* @author Juergen Hoeller |
||||
* @author Chris Beams |
||||
* @author Sam Brannen |
||||
* @since 2.5 |
||||
*/ |
||||
@EnabledForTestGroups(PERFORMANCE) |
||||
public class AnnotationProcessorPerformanceTests { |
||||
|
||||
private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class); |
||||
|
||||
|
||||
@BeforeAll |
||||
public static void commonAssumptions() { |
||||
Assume.notLogging(factoryLog); |
||||
} |
||||
|
||||
@Test |
||||
public void prototypeCreationWithResourcePropertiesIsFastEnough() { |
||||
GenericApplicationContext ctx = createContext(); |
||||
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(ResourceAnnotatedTestBean.class); |
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); |
||||
ctx.registerBeanDefinition("test", rbd); |
||||
ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); |
||||
|
||||
assertFastEnough(ctx); |
||||
} |
||||
|
||||
@Test |
||||
public void prototypeCreationWithOverriddenResourcePropertiesIsFastEnough() { |
||||
GenericApplicationContext ctx = createContext(); |
||||
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(ResourceAnnotatedTestBean.class); |
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); |
||||
rbd.getPropertyValues().add("spouse", new RuntimeBeanReference("spouse")); |
||||
ctx.registerBeanDefinition("test", rbd); |
||||
ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); |
||||
|
||||
assertFastEnough(ctx); |
||||
} |
||||
|
||||
@Test |
||||
public void prototypeCreationWithAutowiredPropertiesIsFastEnough() { |
||||
GenericApplicationContext ctx = createContext(); |
||||
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(AutowiredAnnotatedTestBean.class); |
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); |
||||
ctx.registerBeanDefinition("test", rbd); |
||||
ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); |
||||
|
||||
assertFastEnough(ctx); |
||||
} |
||||
|
||||
@Test |
||||
public void prototypeCreationWithOverriddenAutowiredPropertiesIsFastEnough() { |
||||
GenericApplicationContext ctx = createContext(); |
||||
|
||||
RootBeanDefinition rbd = new RootBeanDefinition(AutowiredAnnotatedTestBean.class); |
||||
rbd.setScope(BeanDefinition.SCOPE_PROTOTYPE); |
||||
rbd.getPropertyValues().add("spouse", new RuntimeBeanReference("spouse")); |
||||
ctx.registerBeanDefinition("test", rbd); |
||||
ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class)); |
||||
|
||||
assertFastEnough(ctx); |
||||
} |
||||
|
||||
private GenericApplicationContext createContext() { |
||||
GenericApplicationContext ctx = new GenericApplicationContext(); |
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx); |
||||
ctx.refresh(); |
||||
return ctx; |
||||
} |
||||
|
||||
private void assertFastEnough(GenericApplicationContext ctx) { |
||||
AtomicBoolean done = new AtomicBoolean(); |
||||
TestBean spouse = ctx.getBean("spouse", TestBean.class); |
||||
Executors.newSingleThreadExecutor().submit(() -> { |
||||
for (int i = 0; i < 100_000; i++) { |
||||
TestBean tb = ctx.getBean("test", TestBean.class); |
||||
assertThat(tb.getSpouse()).isSameAs(spouse); |
||||
} |
||||
done.set(true); |
||||
}); |
||||
|
||||
// "fast enough" is of course relative, but we're using 6 seconds with the hope
|
||||
// that these tests typically pass on the CI server.
|
||||
Awaitility.await() |
||||
.atMost(6, TimeUnit.SECONDS) |
||||
.pollInterval(100, TimeUnit.MILLISECONDS) |
||||
.untilTrue(done); |
||||
} |
||||
|
||||
|
||||
private static class ResourceAnnotatedTestBean extends TestBean { |
||||
|
||||
@Override |
||||
@Resource |
||||
@SuppressWarnings("deprecation") |
||||
@org.springframework.beans.factory.annotation.Required |
||||
public void setSpouse(ITestBean spouse) { |
||||
super.setSpouse(spouse); |
||||
} |
||||
} |
||||
|
||||
private static class AutowiredAnnotatedTestBean extends TestBean { |
||||
|
||||
@Override |
||||
@Autowired |
||||
@SuppressWarnings("deprecation") |
||||
@org.springframework.beans.factory.annotation.Required |
||||
public void setSpouse(ITestBean spouse) { |
||||
super.setSpouse(spouse); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
/* |
||||
* Copyright 2002-2020 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.util; |
||||
|
||||
import java.lang.reflect.Method; |
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark; |
||||
import org.openjdk.jmh.annotations.BenchmarkMode; |
||||
import org.openjdk.jmh.annotations.Mode; |
||||
|
||||
/** |
||||
* Benchmark for finding declared methods on a class using {@link ReflectionUtils}. |
||||
* This benchmark is using {@link Mode#SingleShotTime} since we want to benchmark |
||||
* cold JVM iterations. |
||||
* @author Brian Clozel |
||||
*/ |
||||
@BenchmarkMode(Mode.SingleShotTime) |
||||
public class ReflectionUtilsUniqueDeclaredMethodsBenchmark { |
||||
|
||||
@Benchmark |
||||
public Method[] findMethods() { |
||||
return ReflectionUtils.getUniqueDeclaredMethods(C.class); |
||||
} |
||||
|
||||
@SuppressWarnings("unused") |
||||
class C { |
||||
void m00() { } void m01() { } void m02() { } void m03() { } void m04() { } |
||||
void m05() { } void m06() { } void m07() { } void m08() { } void m09() { } |
||||
void m10() { } void m11() { } void m12() { } void m13() { } void m14() { } |
||||
void m15() { } void m16() { } void m17() { } void m18() { } void m19() { } |
||||
void m20() { } void m21() { } void m22() { } void m23() { } void m24() { } |
||||
void m25() { } void m26() { } void m27() { } void m28() { } void m29() { } |
||||
void m30() { } void m31() { } void m32() { } void m33() { } void m34() { } |
||||
void m35() { } void m36() { } void m37() { } void m38() { } void m39() { } |
||||
void m40() { } void m41() { } void m42() { } void m43() { } void m44() { } |
||||
void m45() { } void m46() { } void m47() { } void m48() { } void m49() { } |
||||
void m50() { } void m51() { } void m52() { } void m53() { } void m54() { } |
||||
void m55() { } void m56() { } void m57() { } void m58() { } void m59() { } |
||||
void m60() { } void m61() { } void m62() { } void m63() { } void m64() { } |
||||
void m65() { } void m66() { } void m67() { } void m68() { } void m69() { } |
||||
void m70() { } void m71() { } void m72() { } void m73() { } void m74() { } |
||||
void m75() { } void m76() { } void m77() { } void m78() { } void m79() { } |
||||
void m80() { } void m81() { } void m82() { } void m83() { } void m84() { } |
||||
void m85() { } void m86() { } void m87() { } void m88() { } void m89() { } |
||||
void m90() { } void m91() { } void m92() { } void m93() { } void m94() { } |
||||
void m95() { } void m96() { } void m97() { } void m98() { } void m99() { } |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
|
||||
/* |
||||
* Copyright 2002-2020 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.expression.spel; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark; |
||||
import org.openjdk.jmh.annotations.BenchmarkMode; |
||||
import org.openjdk.jmh.annotations.Mode; |
||||
import org.openjdk.jmh.annotations.Scope; |
||||
import org.openjdk.jmh.annotations.State; |
||||
|
||||
import org.springframework.expression.EvaluationContext; |
||||
import org.springframework.expression.Expression; |
||||
import org.springframework.expression.ExpressionParser; |
||||
import org.springframework.expression.spel.standard.SpelExpressionParser; |
||||
import org.springframework.expression.spel.support.StandardEvaluationContext; |
||||
|
||||
/** |
||||
* Benchmarks for parsing and executing SpEL expressions. |
||||
* @author Brian Clozel |
||||
*/ |
||||
@BenchmarkMode(Mode.Throughput) |
||||
public class SpelBenchmark { |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class BenchmarkData { |
||||
|
||||
public ExpressionParser parser = new SpelExpressionParser(); |
||||
|
||||
public EvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext(); |
||||
|
||||
} |
||||
|
||||
@Benchmark |
||||
public Object propertyAccessParseAndExecution(BenchmarkData data) { |
||||
Expression expr = data.parser.parseExpression("placeOfBirth.city"); |
||||
return expr.getValue(data.eContext); |
||||
} |
||||
|
||||
@Benchmark |
||||
public Object methodAccessParseAndExecution(BenchmarkData data) { |
||||
Expression expr = data.parser.parseExpression("getPlaceOfBirth().getCity()"); |
||||
return expr.getValue(data.eContext); |
||||
} |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class CachingBenchmarkData extends BenchmarkData { |
||||
|
||||
public Expression propertyExpression; |
||||
|
||||
public Expression methodExpression; |
||||
|
||||
public CachingBenchmarkData() { |
||||
this.propertyExpression = this.parser.parseExpression("placeOfBirth.city"); |
||||
this.methodExpression = this.parser.parseExpression("getPlaceOfBirth().getCity()"); |
||||
} |
||||
} |
||||
|
||||
@Benchmark |
||||
public Object cachingPropertyAccessParseAndExecution(CachingBenchmarkData data) { |
||||
return data.propertyExpression.getValue(data.eContext); |
||||
} |
||||
|
||||
@Benchmark |
||||
public Object cachingMethodAccessParseAndExecution(CachingBenchmarkData data) { |
||||
return data.methodExpression.getValue(data.eContext); |
||||
} |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class ValueBenchmarkData { |
||||
|
||||
public EvaluationContext context; |
||||
|
||||
public Expression expression; |
||||
|
||||
public ValueBenchmarkData() { |
||||
Map<String, String> map = new HashMap<>(); |
||||
map.put("key", "value"); |
||||
this.context = new StandardEvaluationContext(map); |
||||
ExpressionParser spelExpressionParser = new SpelExpressionParser(); |
||||
this.expression = spelExpressionParser.parseExpression("#root['key']"); |
||||
} |
||||
} |
||||
|
||||
@Benchmark |
||||
public Object getValueFromMap(ValueBenchmarkData data) { |
||||
return data.expression.getValue(data.context); |
||||
} |
||||
|
||||
} |
||||
@ -1,134 +0,0 @@
@@ -1,134 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2019 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.expression.spel; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.core.testfixture.EnabledForTestGroups; |
||||
import org.springframework.expression.EvaluationContext; |
||||
import org.springframework.expression.Expression; |
||||
import org.springframework.expression.ExpressionParser; |
||||
import org.springframework.expression.spel.standard.SpelExpressionParser; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.fail; |
||||
import static org.springframework.core.testfixture.TestGroup.PERFORMANCE; |
||||
|
||||
///CLOVER:OFF
|
||||
|
||||
/** |
||||
* Tests the evaluation of real expressions in a real context. |
||||
* |
||||
* @author Andy Clement |
||||
*/ |
||||
@EnabledForTestGroups(PERFORMANCE) |
||||
public class PerformanceTests { |
||||
|
||||
public static final int ITERATIONS = 10000; |
||||
public static final boolean report = true; |
||||
|
||||
private static ExpressionParser parser = new SpelExpressionParser(); |
||||
private static EvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext(); |
||||
|
||||
private static final boolean DEBUG = false; |
||||
|
||||
@Test |
||||
public void testPerformanceOfPropertyAccess() throws Exception { |
||||
long starttime = 0; |
||||
long endtime = 0; |
||||
|
||||
// warmup
|
||||
for (int i = 0; i < ITERATIONS; i++) { |
||||
Expression expr = parser.parseExpression("placeOfBirth.city"); |
||||
assertThat(expr).isNotNull(); |
||||
expr.getValue(eContext); |
||||
} |
||||
|
||||
starttime = System.currentTimeMillis(); |
||||
for (int i = 0; i < ITERATIONS; i++) { |
||||
Expression expr = parser.parseExpression("placeOfBirth.city"); |
||||
assertThat(expr).isNotNull(); |
||||
expr.getValue(eContext); |
||||
} |
||||
endtime = System.currentTimeMillis(); |
||||
long freshParseTime = endtime - starttime; |
||||
if (DEBUG) { |
||||
System.out.println("PropertyAccess: Time for parsing and evaluation x 10000: "+freshParseTime+"ms"); |
||||
} |
||||
|
||||
Expression expr = parser.parseExpression("placeOfBirth.city"); |
||||
assertThat(expr).isNotNull(); |
||||
starttime = System.currentTimeMillis(); |
||||
for (int i = 0; i < ITERATIONS; i++) { |
||||
expr.getValue(eContext); |
||||
} |
||||
endtime = System.currentTimeMillis(); |
||||
long reuseTime = endtime - starttime; |
||||
if (DEBUG) { |
||||
System.out.println("PropertyAccess: Time for just evaluation x 10000: "+reuseTime+"ms"); |
||||
} |
||||
if (reuseTime > freshParseTime) { |
||||
System.out.println("Fresh parse every time, ITERATIONS iterations = " + freshParseTime + "ms"); |
||||
System.out.println("Reuse SpelExpression, ITERATIONS iterations = " + reuseTime + "ms"); |
||||
fail("Should have been quicker to reuse!"); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void testPerformanceOfMethodAccess() throws Exception { |
||||
long starttime = 0; |
||||
long endtime = 0; |
||||
|
||||
// warmup
|
||||
for (int i = 0; i < ITERATIONS; i++) { |
||||
Expression expr = parser.parseExpression("getPlaceOfBirth().getCity()"); |
||||
assertThat(expr).isNotNull(); |
||||
expr.getValue(eContext); |
||||
} |
||||
|
||||
starttime = System.currentTimeMillis(); |
||||
for (int i = 0; i < ITERATIONS; i++) { |
||||
Expression expr = parser.parseExpression("getPlaceOfBirth().getCity()"); |
||||
assertThat(expr).isNotNull(); |
||||
expr.getValue(eContext); |
||||
} |
||||
endtime = System.currentTimeMillis(); |
||||
long freshParseTime = endtime - starttime; |
||||
if (DEBUG) { |
||||
System.out.println("MethodExpression: Time for parsing and evaluation x 10000: "+freshParseTime+"ms"); |
||||
} |
||||
|
||||
Expression expr = parser.parseExpression("getPlaceOfBirth().getCity()"); |
||||
assertThat(expr).isNotNull(); |
||||
starttime = System.currentTimeMillis(); |
||||
for (int i = 0; i < ITERATIONS; i++) { |
||||
expr.getValue(eContext); |
||||
} |
||||
endtime = System.currentTimeMillis(); |
||||
long reuseTime = endtime - starttime; |
||||
if (DEBUG) { |
||||
System.out.println("MethodExpression: Time for just evaluation x 10000: "+reuseTime+"ms"); |
||||
} |
||||
|
||||
if (reuseTime > freshParseTime) { |
||||
System.out.println("Fresh parse every time, ITERATIONS iterations = " + freshParseTime + "ms"); |
||||
System.out.println("Reuse SpelExpression, ITERATIONS iterations = " + reuseTime + "ms"); |
||||
fail("Should have been quicker to reuse!"); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
/* |
||||
* Copyright 2002-2020 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.web.bind; |
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark; |
||||
import org.openjdk.jmh.annotations.BenchmarkMode; |
||||
import org.openjdk.jmh.annotations.Mode; |
||||
import org.openjdk.jmh.annotations.Scope; |
||||
import org.openjdk.jmh.annotations.State; |
||||
|
||||
import org.springframework.web.testfixture.servlet.MockHttpServletRequest; |
||||
|
||||
|
||||
/** |
||||
* Benchmarks for extracting parameters from {@libnk ServletRequest}. |
||||
* @author Brian Clozel |
||||
*/ |
||||
@BenchmarkMode(Mode.Throughput) |
||||
public class ServletRequestUtilsBenchmark { |
||||
|
||||
@State(Scope.Benchmark) |
||||
public static class BenchmarkData { |
||||
|
||||
public MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
|
||||
public String parameterName = "nonExistingParam"; |
||||
} |
||||
|
||||
@Benchmark |
||||
public int intParameterWithDefaultValue(BenchmarkData data) { |
||||
return ServletRequestUtils.getIntParameter(data.request, data.parameterName, 0); |
||||
} |
||||
|
||||
@Benchmark |
||||
public long longParameterWithDefaultValue(BenchmarkData data) { |
||||
return ServletRequestUtils.getLongParameter(data.request, data.parameterName, 0); |
||||
} |
||||
|
||||
@Benchmark |
||||
public float floatParameterWithDefaultValue(BenchmarkData data) { |
||||
return ServletRequestUtils.getFloatParameter(data.request, data.parameterName, 0f); |
||||
} |
||||
|
||||
@Benchmark |
||||
public double doubleParameterWithDefaultValue(BenchmarkData data) { |
||||
return ServletRequestUtils.getDoubleParameter(data.request, data.parameterName, 0d); |
||||
} |
||||
|
||||
@Benchmark |
||||
public boolean booleanParameterWithDefaultValue(BenchmarkData data) { |
||||
return ServletRequestUtils.getBooleanParameter(data.request, data.parameterName, false); |
||||
} |
||||
|
||||
|
||||
@Benchmark |
||||
public String stringParameterWithDefaultValue(BenchmarkData data) { |
||||
return ServletRequestUtils.getStringParameter(data.request, data.parameterName, "defaultValue"); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue