Skip to content

Commit 0f2308e

Browse files
obourgainsbrannen
authored andcommitted
Implement micro performance optimizations
- ClassUtils.isAssignable(): Avoid Map lookup when the type is not a primitive. - AnnotationsScanner: Perform low cost array length check before String comparisons. - BeanFactoryUtils: Use char comparison instead of String comparison. The bean factory prefix is '&', so we can use a char comparison instead of more heavyweight String.startsWith("&"). - AbstractBeanFactory.getMergedBeanDefinition(): Perform the low cost check first. Map lookup, while cheap, is still more expensive than instanceof. Closes gh-34717 Signed-off-by: Olivier Bourgain <[email protected]>
1 parent ee804ee commit 0f2308e

File tree

4 files changed

+14
-5
lines changed

4 files changed

+14
-5
lines changed

Diff for: spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ public abstract class BeanFactoryUtils {
6363
*/
6464
private static final Map<String, String> transformedBeanNameCache = new ConcurrentHashMap<>();
6565

66+
/**
67+
* Used to dereference a {@link FactoryBean} instance and distinguish it from
68+
* beans <i>created</i> by the FactoryBean. For example, if the bean named
69+
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
70+
* will return the factory, not the instance returned by the factory.
71+
*/
72+
private static final char FACTORY_BEAN_PREFIX = BeanFactory.FACTORY_BEAN_PREFIX.charAt(0);
6673

6774
/**
6875
* Return whether the given name is a factory dereference
@@ -72,7 +79,7 @@ public abstract class BeanFactoryUtils {
7279
* @see BeanFactory#FACTORY_BEAN_PREFIX
7380
*/
7481
public static boolean isFactoryDereference(@Nullable String name) {
75-
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
82+
return (name != null && !name.isEmpty() && name.charAt(0) == FACTORY_BEAN_PREFIX);
7683
}
7784

7885
/**
@@ -84,14 +91,14 @@ public static boolean isFactoryDereference(@Nullable String name) {
8491
*/
8592
public static String transformedBeanName(String name) {
8693
Assert.notNull(name, "'name' must not be null");
87-
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
94+
if (!isFactoryDereference(name)) {
8895
return name;
8996
}
9097
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
9198
do {
9299
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
93100
}
94-
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
101+
while (isFactoryDereference(beanName));
95102
return beanName;
96103
});
97104
}

Diff for: spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1153,7 +1153,7 @@ public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
11531153
public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
11541154
String beanName = transformedBeanName(name);
11551155
// Efficiently check whether bean definition exists in this factory.
1156-
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory parent) {
1156+
if (getParentBeanFactory() instanceof ConfigurableBeanFactory parent && !containsBeanDefinition(beanName)) {
11571157
return parent.getMergedBeanDefinition(beanName);
11581158
}
11591159
// Resolve merged bean definition locally.

Diff for: spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java

+1
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ private static <C> Method[] getBaseTypeMethods(C context, Class<?> baseType) {
355355

356356
private static boolean isOverride(Method rootMethod, Method candidateMethod) {
357357
return (!Modifier.isPrivate(candidateMethod.getModifiers()) &&
358+
candidateMethod.getParameterCount() == rootMethod.getParameterCount() &&
358359
candidateMethod.getName().equals(rootMethod.getName()) &&
359360
hasSameParameterTypes(rootMethod, candidateMethod));
360361
}

Diff for: spring-core/src/main/java/org/springframework/util/ClassUtils.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -637,10 +637,11 @@ public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) {
637637
Class<?> resolvedPrimitive = primitiveWrapperTypeMap.get(rhsType);
638638
return (lhsType == resolvedPrimitive);
639639
}
640-
else {
640+
else if (rhsType.isPrimitive()) {
641641
Class<?> resolvedWrapper = primitiveTypeToWrapperMap.get(rhsType);
642642
return (resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper));
643643
}
644+
return false;
644645
}
645646

646647
/**

0 commit comments

Comments
 (0)