Skip to content

SPR-11875: Performance regression for custom autowireBean calls with many properties #570

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.PriorityOrdered;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
Expand Down Expand Up @@ -149,7 +150,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac

/** Cache of filtered PropertyDescriptors: bean Class -> PropertyDescriptor array */
private final Map<Class<?>, PropertyDescriptor[]> filteredPropertyDescriptorsCache =
new ConcurrentHashMap<Class<?>, PropertyDescriptor[]>(64);
new ConcurrentReferenceHashMap<Class<?>, PropertyDescriptor[]>(64);


/**
Expand Down Expand Up @@ -286,7 +287,6 @@ public <T> T createBean(Class<T> beanClass) throws BeansException {
// Use prototype bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
bd.setScope(SCOPE_PROTOTYPE);
bd.allowCaching = false;
return (T) createBean(beanClass.getName(), bd, null);
}

Expand All @@ -295,7 +295,6 @@ public void autowireBean(Object existingBean) {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(ClassUtils.getUserClass(existingBean));
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.allowCaching = false;
BeanWrapper bw = new BeanWrapperImpl(existingBean);
initBeanWrapper(bw);
populateBean(bd.getBeanClass().getName(), bd, bw);
Expand All @@ -315,7 +314,6 @@ public Object configureBean(Object existingBean, String beanName) throws BeansEx
bd = new RootBeanDefinition(mbd);
}
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
bd.allowCaching = false;
}
BeanWrapper bw = new BeanWrapperImpl(existingBean);
initBeanWrapper(bw);
Expand Down Expand Up @@ -1121,7 +1119,7 @@ protected BeanWrapper autowireConstructor(
* @param mbd the bean definition for the bean
* @param bw BeanWrapper with bean instance
*/
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();

if (bw == null) {
Expand Down Expand Up @@ -1177,7 +1175,7 @@ protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
Expand Down Expand Up @@ -1305,51 +1303,34 @@ protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, Be

/**
* Extract a filtered set of PropertyDescriptors from the given BeanWrapper,
* excluding ignored dependency types or properties defined on ignored dependency interfaces.
* excluding ignored dependency types or properties defined on ignored
* dependency interfaces.
* @param bw the BeanWrapper the bean was created with
* @param cache whether to cache filtered PropertyDescriptors for the given bean Class
* @return the filtered PropertyDescriptors
* @see #isExcludedFromDependencyCheck
* @see #filterPropertyDescriptorsForDependencyCheck(org.springframework.beans.BeanWrapper)
*/
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw, boolean cache) {
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) {
PropertyDescriptor[] filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
if (filtered == null) {
if (cache) {
synchronized (this.filteredPropertyDescriptorsCache) {
filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
if (filtered == null) {
filtered = filterPropertyDescriptorsForDependencyCheck(bw);
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
synchronized (this.filteredPropertyDescriptorsCache) {
filtered = this.filteredPropertyDescriptorsCache.get(bw.getWrappedClass());
if (filtered == null) {
List<PropertyDescriptor> pds =
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
PropertyDescriptor pd = it.next();
if (isExcludedFromDependencyCheck(pd)) {
it.remove();
}
}
filtered = pds.toArray(new PropertyDescriptor[pds.size()]);
this.filteredPropertyDescriptorsCache.put(bw.getWrappedClass(), filtered);
}
}
else {
filtered = filterPropertyDescriptorsForDependencyCheck(bw);
}
}
return filtered;
}

/**
* Extract a filtered set of PropertyDescriptors from the given BeanWrapper,
* excluding ignored dependency types or properties defined on ignored dependency interfaces.
* @param bw the BeanWrapper the bean was created with
* @return the filtered PropertyDescriptors
* @see #isExcludedFromDependencyCheck
*/
protected PropertyDescriptor[] filterPropertyDescriptorsForDependencyCheck(BeanWrapper bw) {
List<PropertyDescriptor> pds =
new LinkedList<PropertyDescriptor>(Arrays.asList(bw.getPropertyDescriptors()));
for (Iterator<PropertyDescriptor> it = pds.iterator(); it.hasNext();) {
PropertyDescriptor pd = it.next();
if (isExcludedFromDependencyCheck(pd)) {
it.remove();
}
}
return pds.toArray(new PropertyDescriptor[pds.size()]);
}

/**
* Determine whether the given bean property is excluded from dependency checks.
* <p>This implementation excludes properties defined by CGLIB and
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
Expand Down Expand Up @@ -48,8 +48,6 @@
@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {

boolean allowCaching = true;

private BeanDefinitionHolder decoratedDefinition;

private volatile Class<?> targetType;
Expand Down Expand Up @@ -171,7 +169,6 @@ public RootBeanDefinition(String beanClassName, ConstructorArgumentValues cargs,
*/
public RootBeanDefinition(RootBeanDefinition original) {
super(original);
this.allowCaching = original.allowCaching;
this.decoratedDefinition = original.decoratedDefinition;
this.targetType = original.targetType;
this.isFactoryMethodUnique = original.isFactoryMethodUnique;
Expand Down