Skip to content

Commit

Permalink
Cache DependencyDescriptor per autowired constructor argument
Browse files Browse the repository at this point in the history
Aligned with shortcut handling in AutowiredAnnotationBeanPostProcessor.
Includes minor MethodInvoker optimization for pre-resolved targetClass.

Closes gh-30883
  • Loading branch information
jhoeller committed Jul 15, 2023
1 parent a34f9fa commit 6183f06
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 115 deletions.
Expand Up @@ -705,7 +705,7 @@ protected void inject(Object bean, @Nullable String beanName, @Nullable Property
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
Object value;
Expand All @@ -724,8 +724,7 @@ private Object resolveFieldValue(Field field, Object bean, @Nullable String bean
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName);
}
}
this.cachedFieldValue = cachedFieldValue;
Expand Down Expand Up @@ -805,7 +804,7 @@ private Object[] resolveMethodArguments(Method method, Object bean, @Nullable St
int argumentCount = method.getParameterCount();
Object[] arguments = new Object[argumentCount];
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
Set<String> autowiredBeanNames = new LinkedHashSet<>(argumentCount * 2);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < arguments.length; i++) {
Expand All @@ -814,7 +813,7 @@ private Object[] resolveMethodArguments(Method method, Object bean, @Nullable St
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeanNames, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
Expand All @@ -829,16 +828,16 @@ private Object[] resolveMethodArguments(Method method, Object bean, @Nullable St
if (!this.cached) {
if (arguments != null) {
DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, argumentCount);
registerDependentBeans(beanName, autowiredBeans);
if (autowiredBeans.size() == argumentCount) {
Iterator<String> it = autowiredBeans.iterator();
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == argumentCount) {
Iterator<String> it = autowiredBeanNames.iterator();
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (arguments[i] != null && beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
descriptors[i], autowiredBeanName);
}
}
}
Expand All @@ -864,17 +863,14 @@ private static class ShortcutDependencyDescriptor extends DependencyDescriptor {

private final String shortcut;

private final Class<?> requiredType;

public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut) {
super(original);
this.shortcut = shortcut;
this.requiredType = requiredType;
}

@Override
public Object resolveShortcut(BeanFactory beanFactory) {
return beanFactory.getBean(this.shortcut, this.requiredType);
return beanFactory.getBean(this.shortcut, getDependencyType());
}
}

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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 @@ -62,20 +62,14 @@ static class ShortcutDependencyDescriptor extends DependencyDescriptor {

private final String shortcut;

private final Class<?> requiredType;


public ShortcutDependencyDescriptor(DependencyDescriptor original,
String shortcut, Class<?> requiredType) {
public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut) {
super(original);
this.shortcut = shortcut;
this.requiredType = requiredType;
}


@Override
public Object resolveShortcut(BeanFactory beanFactory) {
return beanFactory.getBean(this.shortcut, this.requiredType);
return beanFactory.getBean(this.shortcut, getDependencyType());
}
}

Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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 @@ -179,8 +179,7 @@ private Object resolveValue(RegisteredBean registeredBean, Field field) {
DependencyDescriptor descriptor = new DependencyDescriptor(field, this.required);
descriptor.setContainingClass(beanClass);
if (this.shortcut != null) {
descriptor = new ShortcutDependencyDescriptor(descriptor, this.shortcut,
field.getType());
descriptor = new ShortcutDependencyDescriptor(descriptor, this.shortcut);
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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 @@ -76,18 +76,16 @@ private AutowiredMethodArgumentsResolver(String methodName, Class<?>[] parameter
this.shortcuts = shortcuts;
}


/**
* Create a new {@link AutowiredMethodArgumentsResolver} for the specified
* method where injection is optional.
* @param methodName the method name
* @param parameterTypes the factory method parameter types
* @return a new {@link AutowiredFieldValueResolver} instance
*/
public static AutowiredMethodArgumentsResolver forMethod(String methodName,
Class<?>... parameterTypes) {

return new AutowiredMethodArgumentsResolver(methodName, parameterTypes, false,
null);
public static AutowiredMethodArgumentsResolver forMethod(String methodName, Class<?>... parameterTypes) {
return new AutowiredMethodArgumentsResolver(methodName, parameterTypes, false, null);
}

/**
Expand All @@ -97,11 +95,8 @@ public static AutowiredMethodArgumentsResolver forMethod(String methodName,
* @param parameterTypes the factory method parameter types
* @return a new {@link AutowiredFieldValueResolver} instance
*/
public static AutowiredMethodArgumentsResolver forRequiredMethod(String methodName,
Class<?>... parameterTypes) {

return new AutowiredMethodArgumentsResolver(methodName, parameterTypes, true,
null);
public static AutowiredMethodArgumentsResolver forRequiredMethod(String methodName, Class<?>... parameterTypes) {
return new AutowiredMethodArgumentsResolver(methodName, parameterTypes, true, null);
}

/**
Expand All @@ -113,8 +108,7 @@ public static AutowiredMethodArgumentsResolver forRequiredMethod(String methodNa
* the shortcuts
*/
public AutowiredMethodArgumentsResolver withShortcut(String... beanNames) {
return new AutowiredMethodArgumentsResolver(this.methodName, this.parameterTypes,
this.required, beanNames);
return new AutowiredMethodArgumentsResolver(this.methodName, this.parameterTypes, this.required, beanNames);
}

/**
Expand All @@ -123,9 +117,7 @@ public AutowiredMethodArgumentsResolver withShortcut(String... beanNames) {
* @param registeredBean the registered bean
* @param action the action to execute with the resolved method arguments
*/
public void resolve(RegisteredBean registeredBean,
ThrowingConsumer<AutowiredArguments> action) {

public void resolve(RegisteredBean registeredBean, ThrowingConsumer<AutowiredArguments> action) {
Assert.notNull(registeredBean, "'registeredBean' must not be null");
Assert.notNull(action, "'action' must not be null");
AutowiredArguments resolved = resolve(registeredBean);
Expand Down Expand Up @@ -177,25 +169,22 @@ private AutowiredArguments resolveArguments(RegisteredBean registeredBean,
TypeConverter typeConverter = beanFactory.getTypeConverter();
for (int i = 0; i < argumentCount; i++) {
MethodParameter parameter = new MethodParameter(method, i);
DependencyDescriptor descriptor = new DependencyDescriptor(parameter,
this.required);
DependencyDescriptor descriptor = new DependencyDescriptor(parameter, this.required);
descriptor.setContainingClass(beanClass);
String shortcut = (this.shortcuts != null) ? this.shortcuts[i] : null;
String shortcut = (this.shortcuts != null ? this.shortcuts[i] : null);
if (shortcut != null) {
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut,
parameter.getParameterType());
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut);
}
try {
Object argument = autowireCapableBeanFactory.resolveDependency(descriptor,
beanName, autowiredBeanNames, typeConverter);
Object argument = autowireCapableBeanFactory.resolveDependency(
descriptor, beanName, autowiredBeanNames, typeConverter);
if (argument == null && !this.required) {
return null;
}
arguments[i] = argument;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName,
new InjectionPoint(parameter), ex);
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(parameter), ex);
}
}
registerDependentBeans(beanFactory, beanName, autowiredBeanNames);
Expand Down
Expand Up @@ -248,18 +248,18 @@ private AutowiredArguments resolveArguments(RegisteredBean registeredBean, Execu
() -> "'shortcuts' must contain " + resolved.length + " elements");

ConstructorArgumentValues argumentValues = resolveArgumentValues(registeredBean);
Set<String> autowiredBeans = new LinkedHashSet<>(resolved.length);
Set<String> autowiredBeanNames = new LinkedHashSet<>(resolved.length * 2);
for (int i = startIndex; i < parameterCount; i++) {
MethodParameter parameter = getMethodParameter(executable, i);
DependencyDescriptor descriptor = new DependencyDescriptor(parameter, true);
String shortcut = (this.shortcuts != null ? this.shortcuts[i - startIndex] : null);
if (shortcut != null) {
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut, registeredBean.getBeanClass());
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut);
}
ValueHolder argumentValue = argumentValues.getIndexedArgumentValue(i, null);
resolved[i - startIndex] = resolveArgument(registeredBean, descriptor, argumentValue, autowiredBeans);
resolved[i - startIndex] = resolveArgument(registeredBean, descriptor, argumentValue, autowiredBeanNames);
}
registerDependentBeans(registeredBean.getBeanFactory(), registeredBean.getBeanName(), autowiredBeans);
registerDependentBeans(registeredBean.getBeanFactory(), registeredBean.getBeanName(), autowiredBeanNames);

return AutowiredArguments.of(resolved);
}
Expand Down Expand Up @@ -302,7 +302,7 @@ private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver, V

@Nullable
private Object resolveArgument(RegisteredBean registeredBean, DependencyDescriptor descriptor,
@Nullable ValueHolder argumentValue, Set<String> autowiredBeans) {
@Nullable ValueHolder argumentValue, Set<String> autowiredBeanNames) {

TypeConverter typeConverter = registeredBean.getBeanFactory().getTypeConverter();
if (argumentValue != null) {
Expand All @@ -311,7 +311,7 @@ private Object resolveArgument(RegisteredBean registeredBean, DependencyDescript
descriptor.getDependencyType(), descriptor.getMethodParameter()));
}
try {
return registeredBean.resolveAutowiredArgument(descriptor, typeConverter, autowiredBeans);
return registeredBean.resolveAutowiredArgument(descriptor, typeConverter, autowiredBeanNames);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, registeredBean.getBeanName(), descriptor, ex);
Expand Down
Expand Up @@ -1483,8 +1483,8 @@ protected void autowireByType(
converter = bw;
}

Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
Set<String> autowiredBeanNames = new LinkedHashSet<>(propertyNames.length * 2);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
Expand Down
Expand Up @@ -153,7 +153,7 @@ else if (value instanceof BeanDefinition bd) {
(name, mbd) -> resolveInnerBeanValue(argName, name, mbd));
}
else if (value instanceof DependencyDescriptor dependencyDescriptor) {
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
Object result = this.beanFactory.resolveDependency(
dependencyDescriptor, this.beanName, autowiredBeanNames, this.typeConverter);
for (String autowiredBeanName : autowiredBeanNames) {
Expand Down

0 comments on commit 6183f06

Please sign in to comment.