Add public method to get bean order on DefaultListableBeanFactory

Closes gh-34712
This commit is contained in:
Juergen Hoeller 2025-06-26 14:48:07 +02:00
parent c5da405314
commit 841d9fb73b
4 changed files with 52 additions and 9 deletions

View File

@ -29,6 +29,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.Iterator;
@ -2315,6 +2316,33 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return (result instanceof Optional<?> optional ? optional : Optional.ofNullable(result));
}
/**
* Public method to determine the applicable order value for a given bean.
* <p>This variant implicitly obtains a corresponding bean instance from this factory.
* @param beanName the name of the bean
* @return the corresponding order value (default is {@link Ordered#LOWEST_PRECEDENCE})
* @since 7.0
* @see #getOrder(String, Object)
*/
public int getOrder(String beanName) {
return getOrder(beanName, getBean(beanName));
}
/**
* Public method to determine the applicable order value for a given bean.
* @param beanName the name of the bean
* @param beanInstance the bean instance to check
* @return the corresponding order value (default is {@link Ordered#LOWEST_PRECEDENCE})
* @since 7.0
* @see #getOrder(String)
*/
public int getOrder(String beanName, Object beanInstance) {
OrderComparator comparator = (getDependencyComparator() instanceof OrderComparator orderComparator ?
orderComparator : OrderComparator.INSTANCE);
return comparator.getOrder(beanInstance,
new FactoryAwareOrderSourceProvider(Collections.singletonMap(beanInstance, beanName)));
}
@Override
public String toString() {
@ -2672,7 +2700,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return null;
}
try {
RootBeanDefinition beanDefinition = (RootBeanDefinition) getMergedBeanDefinition(beanName);
BeanDefinition beanDefinition = getMergedBeanDefinition(beanName);
List<Object> sources = new ArrayList<>(3);
Object orderAttribute = beanDefinition.getAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE);
if (orderAttribute != null) {
@ -2684,14 +2712,16 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
AbstractBeanDefinition.ORDER_ATTRIBUTE + "': " + orderAttribute.getClass().getName());
}
}
Method factoryMethod = beanDefinition.getResolvedFactoryMethod();
if (beanDefinition instanceof RootBeanDefinition rootBeanDefinition) {
Method factoryMethod = rootBeanDefinition.getResolvedFactoryMethod();
if (factoryMethod != null) {
sources.add(factoryMethod);
}
Class<?> targetType = beanDefinition.getTargetType();
Class<?> targetType = rootBeanDefinition.getTargetType();
if (targetType != null && targetType != obj.getClass()) {
sources.add(targetType);
}
}
return sources.toArray();
}
catch (NoSuchBeanDefinitionException ex) {

View File

@ -1542,6 +1542,7 @@ class DefaultListableBeanFactoryTests {
bd2.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.HIGHEST_PRECEDENCE);
bd2.setScope(BeanDefinition.SCOPE_PROTOTYPE);
lbf.registerBeanDefinition("bean2", bd2);
assertThat(lbf.getBeanProvider(TestBean.class).orderedStream().map(TestBean::getName))
.containsExactly("highest", "lowest");
assertThat(lbf.getBeanProvider(TestBean.class).orderedStream(clazz -> !DerivedTestBean.class.isAssignableFrom(clazz))
@ -1550,6 +1551,9 @@ class DefaultListableBeanFactoryTests {
.containsExactly("highest", "lowest");
assertThat(lbf.getBeanProvider(TestBean.class).orderedStream(ObjectProvider.UNFILTERED, false).map(TestBean::getName))
.containsExactly("lowest");
assertThat(lbf.getOrder("bean1")).isEqualTo(Ordered.LOWEST_PRECEDENCE);
assertThat(lbf.getOrder("bean2")).isEqualTo(Ordered.HIGHEST_PRECEDENCE);
}
@Test
@ -1562,12 +1566,16 @@ class DefaultListableBeanFactoryTests {
rbd2.setAttribute(AbstractBeanDefinition.ORDER_ATTRIBUTE, Ordered.LOWEST_PRECEDENCE);
rbd2.setScope(BeanDefinition.SCOPE_PROTOTYPE);
lbf.registerBeanDefinition("highestPrecedenceFactory", rbd2);
assertThat(lbf.getBeanProvider(TestBean.class).orderedStream().map(TestBean::getName))
.containsExactly("fromLowestPrecedenceTestBeanFactoryBean", "fromHighestPrecedenceTestBeanFactoryBean");
assertThat(lbf.getBeanProvider(TestBean.class).orderedStream(ObjectProvider.UNFILTERED).map(TestBean::getName))
.containsExactly("fromLowestPrecedenceTestBeanFactoryBean", "fromHighestPrecedenceTestBeanFactoryBean");
assertThat(lbf.getBeanProvider(TestBean.class).orderedStream(ObjectProvider.UNFILTERED, false).map(TestBean::getName))
.containsExactly("fromLowestPrecedenceTestBeanFactoryBean");
assertThat(lbf.getOrder("lowestPrecedenceFactory")).isEqualTo(Ordered.HIGHEST_PRECEDENCE);
assertThat(lbf.getOrder("highestPrecedenceFactory")).isEqualTo(Ordered.LOWEST_PRECEDENCE);
}
@Test
@ -1579,6 +1587,7 @@ class DefaultListableBeanFactoryTests {
GenericBeanDefinition bd2 = new GenericBeanDefinition();
bd2.setBeanClass(TestBean.class);
lbf.registerBeanDefinition("bean", bd2);
assertThatIllegalStateException()
.isThrownBy(() -> lbf.getBeanProvider(TestBean.class).orderedStream().collect(Collectors.toList()))
.withMessageContaining("Invalid value type for attribute");

View File

@ -44,6 +44,9 @@ class Gh29105Tests {
Stream<Class<?>> orderedTypes = child.getBeanProvider(MyService.class).orderedStream().map(Object::getClass);
assertThat(orderedTypes).containsExactly(CustomService.class, DefaultService.class);
assertThat(child.getDefaultListableBeanFactory().getOrder("defaultService")).isEqualTo(0);
assertThat(child.getDefaultListableBeanFactory().getOrder("customService")).isEqualTo(-1);
child.close();
parent.close();
}

View File

@ -95,8 +95,9 @@ public class OrderComparator implements Comparator<Object> {
* using {@link #findOrder} and falls back to a regular {@link #getOrder(Object)} call.
* @param obj the object to check
* @return the order value, or {@code Ordered.LOWEST_PRECEDENCE} as fallback
* @since 7.0
*/
private int getOrder(@Nullable Object obj, @Nullable OrderSourceProvider sourceProvider) {
public int getOrder(@Nullable Object obj, @Nullable OrderSourceProvider sourceProvider) {
Integer order = null;
if (obj != null && sourceProvider != null) {
Object orderSource = sourceProvider.getOrderSource(obj);