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 <olivierbourgain02@gmail.com>
This commit is contained in:
parent
ee804ee8fb
commit
0f2308e85f
|
@ -63,6 +63,13 @@ public abstract class BeanFactoryUtils {
|
|||
*/
|
||||
private static final Map<String, String> transformedBeanNameCache = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Used to dereference a {@link FactoryBean} instance and distinguish it from
|
||||
* beans <i>created</i> by the FactoryBean. For example, if the bean named
|
||||
* {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
|
||||
* will return the factory, not the instance returned by the factory.
|
||||
*/
|
||||
private static final char FACTORY_BEAN_PREFIX = BeanFactory.FACTORY_BEAN_PREFIX.charAt(0);
|
||||
|
||||
/**
|
||||
* Return whether the given name is a factory dereference
|
||||
|
@ -72,7 +79,7 @@ public abstract class BeanFactoryUtils {
|
|||
* @see BeanFactory#FACTORY_BEAN_PREFIX
|
||||
*/
|
||||
public static boolean isFactoryDereference(@Nullable String name) {
|
||||
return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
|
||||
return (name != null && !name.isEmpty() && name.charAt(0) == FACTORY_BEAN_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,14 +91,14 @@ public abstract class BeanFactoryUtils {
|
|||
*/
|
||||
public static String transformedBeanName(String name) {
|
||||
Assert.notNull(name, "'name' must not be null");
|
||||
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
|
||||
if (!isFactoryDereference(name)) {
|
||||
return name;
|
||||
}
|
||||
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
|
||||
do {
|
||||
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
|
||||
}
|
||||
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
|
||||
while (isFactoryDereference(beanName));
|
||||
return beanName;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1153,7 +1153,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
|
||||
String beanName = transformedBeanName(name);
|
||||
// Efficiently check whether bean definition exists in this factory.
|
||||
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory parent) {
|
||||
if (getParentBeanFactory() instanceof ConfigurableBeanFactory parent && !containsBeanDefinition(beanName)) {
|
||||
return parent.getMergedBeanDefinition(beanName);
|
||||
}
|
||||
// Resolve merged bean definition locally.
|
||||
|
|
|
@ -355,6 +355,7 @@ abstract class AnnotationsScanner {
|
|||
|
||||
private static boolean isOverride(Method rootMethod, Method candidateMethod) {
|
||||
return (!Modifier.isPrivate(candidateMethod.getModifiers()) &&
|
||||
candidateMethod.getParameterCount() == rootMethod.getParameterCount() &&
|
||||
candidateMethod.getName().equals(rootMethod.getName()) &&
|
||||
hasSameParameterTypes(rootMethod, candidateMethod));
|
||||
}
|
||||
|
|
|
@ -637,10 +637,11 @@ public abstract class ClassUtils {
|
|||
Class<?> resolvedPrimitive = primitiveWrapperTypeMap.get(rhsType);
|
||||
return (lhsType == resolvedPrimitive);
|
||||
}
|
||||
else {
|
||||
else if (rhsType.isPrimitive()) {
|
||||
Class<?> resolvedWrapper = primitiveTypeToWrapperMap.get(rhsType);
|
||||
return (resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue