diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java index 8e113a729f78..d9fca954f209 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/BeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 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. @@ -19,6 +19,7 @@ import org.jspecify.annotations.Nullable; import org.springframework.beans.BeansException; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ResolvableType; /** @@ -99,6 +100,7 @@ * @author Rod Johnson * @author Juergen Hoeller * @author Chris Beams + * @author Yanming Zhou * @since 13 April 2001 * @see BeanNameAware#setBeanName * @see BeanClassLoaderAware#setBeanClassLoader @@ -201,6 +203,25 @@ public interface BeanFactory { */ T getBean(Class requiredType) throws BeansException; + /** + * Return the bean instance that uniquely matches the given object type, if any. + *

This method goes into {@link ListableBeanFactory} by-type lookup territory + * but may also be translated into a conventional by-name lookup based on the name + * of the given type. For more extensive retrieval operations across sets of beans, + * use {@link ListableBeanFactory} and/or {@link BeanFactoryUtils}. + * @param typeReference the reference to obtain type the bean must match + * @return an instance of the single bean matching the required type + * @throws NoSuchBeanDefinitionException if no bean of the given type was found + * @throws NoUniqueBeanDefinitionException if more than one bean of the given type was found + * @throws BeansException if the bean could not be created + * @since 7.0 + * @see #getBean(Class) + */ + default T getBean(ParameterizedTypeReference typeReference) throws BeansException { + ObjectProvider provider = getBeanProvider(ResolvableType.forType(typeReference)); + return provider.getObject(); + } + /** * Return an instance, which may be shared or independent, of the specified bean. *

Allows for specifying explicit constructor arguments / factory method arguments, diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java index 4f8e0d9abf30..048d6e2998ed 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java @@ -80,6 +80,7 @@ import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.MethodParameter; import org.springframework.core.Ordered; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.Order; @@ -1651,6 +1652,22 @@ void getBeanByTypeWithAmbiguity() { lbf.getBean(TestBean.class)); } + @Test + void getBeanByTypeReference() { + RootBeanDefinition bd1 = new RootBeanDefinition(StringTemplate.class); + RootBeanDefinition bd2 = new RootBeanDefinition(NumberTemplate.class); + lbf.registerBeanDefinition("bd1", bd1); + lbf.registerBeanDefinition("bd2", bd2); + + Template stringTemplate = lbf.getBean(new ParameterizedTypeReference<>() { + }); + Template numberTemplate = lbf.getBean(new ParameterizedTypeReference<>() { + }); + + assertThat(stringTemplate).isInstanceOf(StringTemplate.class); + assertThat(numberTemplate).isInstanceOf(NumberTemplate.class); + } + @Test void getBeanByTypeWithPrimary() { RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class); @@ -3814,4 +3831,16 @@ public Class getObjectType() { } } + private static class Template { + + } + + private static class StringTemplate extends Template { + + } + + private static class NumberTemplate extends Template { + + } + }