diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionCustomizer.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionCustomizer.java new file mode 100644 index 0000000000..90fcc0b21a --- /dev/null +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinitionCustomizer.java @@ -0,0 +1,35 @@ +/* + * Copyright 2002-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.beans.factory.config; + +/** + * Callback for customizing a given bean definition. + * Designed for use with a lambda expression or method reference. + * + * @author Juergen Hoeller + * @since 5.0 + * @see org.springframework.beans.factory.support.BeanDefinitionBuilder#applyCustomizers + */ +@FunctionalInterface +public interface BeanDefinitionCustomizer { + + /** + * Customize the given bean definition. + */ + void customize(BeanDefinition bd); + +} diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionBuilder.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionBuilder.java index 7ff6ef06df..3f7aed7d89 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionBuilder.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionBuilder.java @@ -16,6 +16,9 @@ package org.springframework.beans.factory.support; +import java.util.function.Supplier; + +import org.springframework.beans.factory.config.BeanDefinitionCustomizer; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.util.ObjectUtils; @@ -41,6 +44,17 @@ public class BeanDefinitionBuilder { return builder; } + /** + * Create a new {@code BeanDefinitionBuilder} used to construct a {@link GenericBeanDefinition}. + * @param beanClassName the class name for the bean that the definition is being created for + */ + public static BeanDefinitionBuilder genericBeanDefinition(String beanClassName) { + BeanDefinitionBuilder builder = new BeanDefinitionBuilder(); + builder.beanDefinition = new GenericBeanDefinition(); + builder.beanDefinition.setBeanClassName(beanClassName); + return builder; + } + /** * Create a new {@code BeanDefinitionBuilder} used to construct a {@link GenericBeanDefinition}. * @param beanClass the {@code Class} of the bean that the definition is being created for @@ -54,33 +68,15 @@ public class BeanDefinitionBuilder { /** * Create a new {@code BeanDefinitionBuilder} used to construct a {@link GenericBeanDefinition}. - * @param beanClassName the class name for the bean that the definition is being created for + * @param beanClass the {@code Class} of the bean that the definition is being created for + * @param instanceSupplier a callback for creating an instance of the bean + * @since 5.0 */ - public static BeanDefinitionBuilder genericBeanDefinition(String beanClassName) { + public static BeanDefinitionBuilder genericBeanDefinition(Class beanClass, Supplier instanceSupplier) { BeanDefinitionBuilder builder = new BeanDefinitionBuilder(); builder.beanDefinition = new GenericBeanDefinition(); - builder.beanDefinition.setBeanClassName(beanClassName); - return builder; - } - - /** - * Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}. - * @param beanClass the {@code Class} of the bean that the definition is being created for - */ - public static BeanDefinitionBuilder rootBeanDefinition(Class beanClass) { - return rootBeanDefinition(beanClass, null); - } - - /** - * Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}. - * @param beanClass the {@code Class} of the bean that the definition is being created for - * @param factoryMethodName the name of the method to use to construct the bean instance - */ - public static BeanDefinitionBuilder rootBeanDefinition(Class beanClass, String factoryMethodName) { - BeanDefinitionBuilder builder = new BeanDefinitionBuilder(); - builder.beanDefinition = new RootBeanDefinition(); builder.beanDefinition.setBeanClass(beanClass); - builder.beanDefinition.setFactoryMethodName(factoryMethodName); + builder.beanDefinition.setInstanceSupplier(instanceSupplier); return builder; } @@ -105,6 +101,27 @@ public class BeanDefinitionBuilder { return builder; } + /** + * Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}. + * @param beanClass the {@code Class} of the bean that the definition is being created for + */ + public static BeanDefinitionBuilder rootBeanDefinition(Class beanClass) { + return rootBeanDefinition(beanClass, null); + } + + /** + * Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}. + * @param beanClass the {@code Class} of the bean that the definition is being created for + * @param factoryMethodName the name of the method to use to construct the bean instance + */ + public static BeanDefinitionBuilder rootBeanDefinition(Class beanClass, String factoryMethodName) { + BeanDefinitionBuilder builder = new BeanDefinitionBuilder(); + builder.beanDefinition = new RootBeanDefinition(); + builder.beanDefinition.setBeanClass(beanClass); + builder.beanDefinition.setFactoryMethodName(factoryMethodName); + return builder; + } + /** * Create a new {@code BeanDefinitionBuilder} used to construct a {@link ChildBeanDefinition}. * @param parentName the name of the parent bean @@ -286,4 +303,17 @@ public class BeanDefinitionBuilder { return this; } + /** + * Apply the given customizers to the underlying bean definition. + * @since 5.0 + */ + public BeanDefinitionBuilder applyCustomizers(BeanDefinitionCustomizer... customizers) { + if (customizers != null) { + for (BeanDefinitionCustomizer customizer : customizers) { + customizer.customize(beanDefinition); + } + } + return this; + } + } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java index 2501ed0dfa..e28f41d9d1 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotatedBeanDefinitionReader.java @@ -19,8 +19,9 @@ package org.springframework.context.annotation; import java.lang.annotation.Annotation; import java.util.function.Supplier; -import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionCustomizer; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.AutowireCandidateQualifier; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; @@ -139,9 +140,35 @@ public class AnnotatedBeanDefinitionReader { * class-declared annotations. * @param annotatedClass the class of the bean */ - @SuppressWarnings("unchecked") public void registerBean(Class annotatedClass) { - registerBean(annotatedClass, null, null, (Class[]) null); + doRegisterBean(annotatedClass, null, null, null); + } + + /** + * Register a bean from the given bean class, deriving its metadata from + * class-declared annotations, using the given supplier for obtaining a new + * instance (possibly declared as a lambda expression or method reference). + * @param annotatedClass the class of the bean + * @param instanceSupplier a callback for creating an instance of the bean + * (may be {@code null}) + * @since 5.0 + */ + public void registerBean(Class annotatedClass, Supplier instanceSupplier) { + doRegisterBean(annotatedClass, instanceSupplier, null, null); + } + + /** + * Register a bean from the given bean class, deriving its metadata from + * class-declared annotations, using the given supplier for obtaining a new + * instance (possibly declared as a lambda expression or method reference). + * @param annotatedClass the class of the bean + * @param name an explicit name for the bean + * @param instanceSupplier a callback for creating an instance of the bean + * (may be {@code null}) + * @since 5.0 + */ + public void registerBean(Class annotatedClass, String name, Supplier instanceSupplier) { + doRegisterBean(annotatedClass, instanceSupplier, name, null); } /** @@ -153,7 +180,7 @@ public class AnnotatedBeanDefinitionReader { */ @SuppressWarnings("unchecked") public void registerBean(Class annotatedClass, Class... qualifiers) { - registerBean(annotatedClass, null, null, qualifiers); + doRegisterBean(annotatedClass, null, null, qualifiers); } /** @@ -166,23 +193,7 @@ public class AnnotatedBeanDefinitionReader { */ @SuppressWarnings("unchecked") public void registerBean(Class annotatedClass, String name, Class... qualifiers) { - registerBean(annotatedClass, null, name, qualifiers); - } - - /** - * Register a bean from the given bean class, deriving its metadata from - * class-declared annotations, using the given supplier for obtaining a new - * instance (possibly declared as a lambda expression or method reference). - * @param annotatedClass the class of the bean - * @param instanceSupplier a callback for creating an instance of the bean - * (may be {@code null}) - * @return the registered bean definition, or {@code null} if skipped due to - * a declared condition - * @since 5.0 - */ - @SuppressWarnings("unchecked") - public AnnotatedBeanDefinition registerBean(Class annotatedClass, Supplier instanceSupplier) { - return registerBean(annotatedClass, instanceSupplier, null, (Class[]) null); + doRegisterBean(annotatedClass, null, name, qualifiers); } /** @@ -194,23 +205,23 @@ public class AnnotatedBeanDefinitionReader { * @param name an explicit name for the bean * @param qualifiers specific qualifier annotations to consider, if any, * in addition to qualifiers at the bean class level - * @return the registered bean definition, or {@code null} if skipped due to - * a declared condition + * @param definitionCustomizers one or more callbacks for customizing the + * factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag * @since 5.0 */ - @SuppressWarnings("unchecked") - public AnnotatedBeanDefinition registerBean(Class annotatedClass, Supplier instanceSupplier, - String name, Class... qualifiers) { + void doRegisterBean(Class annotatedClass, Supplier instanceSupplier, String name, + Class[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass); if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { - return null; + return; } abd.setInstanceSupplier(instanceSupplier); ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); + AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) { for (Class qualifier : qualifiers) { @@ -225,11 +236,15 @@ public class AnnotatedBeanDefinitionReader { } } } + if (definitionCustomizers != null) { + for (BeanDefinitionCustomizer customizer : definitionCustomizers) { + customizer.customize(abd); + } + } BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); - return abd; } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java index 3e553e257d..eac46b98e6 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/AnnotationConfigApplicationContext.java @@ -18,7 +18,7 @@ package org.springframework.context.annotation; import java.util.function.Supplier; -import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionCustomizer; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.support.GenericApplicationContext; @@ -181,36 +181,6 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex // Convenient methods for registering individual beans //--------------------------------------------------------------------- - /** - * Register a bean from the given bean class, deriving its metadata from - * class-declared annotations, using the given supplier for obtaining a new - * instance (possibly declared as a lambda expression or method reference). - *

The bean name will be generated according to annotated component rules. - * @param annotatedClass the class of the bean - * @param instanceSupplier a callback for creating an instance of the bean - * @since 5.0 - * @see #setBeanNameGenerator - */ - @SuppressWarnings("unchecked") - public void registerBean(Class annotatedClass, Supplier instanceSupplier) { - registerBean(null, annotatedClass, instanceSupplier); - } - - /** - * Register a bean from the given bean class, deriving its metadata from - * class-declared annotations, using the given supplier for obtaining a new - * instance (possibly declared as a lambda expression or method reference). - * @param beanName the name of the bean (may be {@code null}) - * @param annotatedClass the class of the bean - * @param instanceSupplier a callback for creating an instance of the bean - * @since 5.0 - */ - @SuppressWarnings("unchecked") - public void registerBean(String beanName, Class annotatedClass, Supplier instanceSupplier) { - Assert.notNull(instanceSupplier, "Supplier must not be null"); - this.reader.registerBean(annotatedClass, instanceSupplier, beanName); - } - /** * Register a bean from the given bean class, deriving its metadata from * class-declared annotations, and optionally providing explicit constructor @@ -222,9 +192,7 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex * specific ones, with the rest to be resolved through regular autowiring * (may be {@code null} or empty) * @since 5.0 - * @see #setBeanNameGenerator */ - @SuppressWarnings("unchecked") public void registerBean(Class annotatedClass, Object... constructorArguments) { registerBean(null, annotatedClass, constructorArguments); } @@ -241,14 +209,20 @@ public class AnnotationConfigApplicationContext extends GenericApplicationContex * (may be {@code null} or empty) * @since 5.0 */ - @SuppressWarnings("unchecked") public void registerBean(String beanName, Class annotatedClass, Object... constructorArguments) { - AnnotatedBeanDefinition abd = this.reader.registerBean(annotatedClass, null, beanName); - if (constructorArguments != null) { - for (Object arg : constructorArguments) { - abd.getConstructorArgumentValues().addGenericArgumentValue(arg); - } - } + this.reader.doRegisterBean(annotatedClass, null, beanName, null, + bd -> { + for (Object arg : constructorArguments) { + bd.getConstructorArgumentValues().addGenericArgumentValue(arg); + } + }); + } + + @Override + public void registerBean(String beanName, Class beanClass, Supplier supplier, + BeanDefinitionCustomizer... customizers) { + + this.reader.doRegisterBean(beanClass, supplier, beanName, null, customizers); } } diff --git a/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java index c2a5e85434..5e0fc34b07 100644 --- a/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java @@ -18,13 +18,16 @@ package org.springframework.context.support; import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionCustomizer; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; @@ -350,4 +353,74 @@ public class GenericApplicationContext extends AbstractApplicationContext implem return this.beanFactory.isAlias(beanName); } + + //--------------------------------------------------------------------- + // Convenient methods for registering individual beans + //--------------------------------------------------------------------- + + /** + * Register a bean from the given bean class, optionally customizing its + * bean definition metadata (typically declared as a lambda expression + * or method reference). + * @param beanClass the class of the bean + * @param customizers one or more callbacks for customizing the + * factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag + * @since 5.0 + */ + public void registerBean(Class beanClass, BeanDefinitionCustomizer... customizers) { + registerBean(null, beanClass, null, customizers); + } + + /** + * Register a bean from the given bean class, using the given supplier for + * obtaining a new instance (typically declared as a lambda expression or + * method reference), optionally customizing its bean definition metadata + * (again typically declared as a lambda expression or method reference). + * @param beanName the name of the bean (may be {@code null}) + * @param beanClass the class of the bean + * @param customizers one or more callbacks for customizing the + * factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag + * @since 5.0 + */ + public void registerBean(String beanName, Class beanClass, BeanDefinitionCustomizer... customizers) { + registerBean(beanName, beanClass, null, customizers); + } + + /** + * Register a bean from the given bean class, using the given supplier for + * obtaining a new instance (typically declared as a lambda expression or + * method reference), optionally customizing its bean definition metadata + * (again typically declared as a lambda expression or method reference). + * @param beanClass the class of the bean + * @param supplier a callback for creating an instance of the bean + * @param customizers one or more callbacks for customizing the + * factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag + * @since 5.0 + */ + public void registerBean(Class beanClass, Supplier supplier, BeanDefinitionCustomizer... customizers) { + registerBean(null, beanClass, supplier, customizers); + } + + /** + * Register a bean from the given bean class, using the given supplier for + * obtaining a new instance (typically declared as a lambda expression or + * method reference), optionally customizing its bean definition metadata + * (again typically declared as a lambda expression or method reference). + * @param beanName the name of the bean (may be {@code null}) + * @param beanClass the class of the bean + * @param supplier a callback for creating an instance of the bean + * @param customizers one or more callbacks for customizing the + * factory's {@link BeanDefinition}, e.g. setting a lazy-init or primary flag + * @since 5.0 + */ + public void registerBean(String beanName, Class beanClass, Supplier supplier, + BeanDefinitionCustomizer... customizers) { + + Assert.isTrue(beanName != null || beanClass != null, "Either bean name or bean class must be specified"); + String nameToUse = (beanName != null ? beanName : beanClass.getName()); + BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(beanClass, supplier). + applyCustomizers(customizers).getRawBeanDefinition(); + registerBeanDefinition(nameToUse, beanDefinition); + } + } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java b/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java index 3d18a9b153..6e15d1f976 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java @@ -52,6 +52,7 @@ public class AnnotationConfigApplicationContextTests { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.scan("org.springframework.context.annotation6"); context.refresh(); + context.getBean(uncapitalize(ConfigForScanning.class.getSimpleName())); context.getBean("testBean"); // contributed by ConfigForScanning context.getBean(uncapitalize(ComponentForScanning.class.getSimpleName())); @@ -65,6 +66,7 @@ public class AnnotationConfigApplicationContextTests { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(Config.class, NameConfig.class); context.refresh(); + context.getBean("testBean"); context.getBean("name"); Map beans = context.getBeansWithAnnotation(Configuration.class); @@ -76,6 +78,7 @@ public class AnnotationConfigApplicationContextTests { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(Config.class, NameConfig.class, UntypedFactoryBean.class); context.refresh(); + context.getBean("testBean"); context.getBean("name"); Map beans = context.getBeansWithAnnotation(Configuration.class); @@ -121,6 +124,7 @@ public class AnnotationConfigApplicationContextTests { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(BeanA.class, BeanB.class, BeanC.class); context.refresh(); + assertSame(context.getBean(BeanB.class), context.getBean(BeanA.class).b); assertSame(context.getBean(BeanC.class), context.getBean(BeanA.class).c); assertSame(context, context.getBean(BeanB.class).applicationContext); @@ -133,6 +137,7 @@ public class AnnotationConfigApplicationContextTests { context.registerBean("b", BeanB.class); context.registerBean("c", BeanC.class); context.refresh(); + assertSame(context.getBean("b"), context.getBean("a", BeanA.class).b); assertSame(context.getBean("c"), context.getBean("a", BeanA.class).c); assertSame(context, context.getBean("b", BeanB.class).applicationContext); @@ -146,6 +151,24 @@ public class AnnotationConfigApplicationContextTests { context.registerBean(BeanB.class, BeanB::new); context.registerBean(BeanC.class, BeanC::new); context.refresh(); + + assertTrue(context.getBeanFactory().containsSingleton("annotationConfigApplicationContextTests.BeanA")); + assertSame(context.getBean(BeanB.class), context.getBean(BeanA.class).b); + assertSame(context.getBean(BeanC.class), context.getBean(BeanA.class).c); + assertSame(context, context.getBean(BeanB.class).applicationContext); + } + + @Test + public void individualBeanWithSupplierAndCustomizer() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.registerBean(BeanA.class, + () -> new BeanA(context.getBean(BeanB.class), context.getBean(BeanC.class)), + bd -> bd.setLazyInit(true)); + context.registerBean(BeanB.class, BeanB::new); + context.registerBean(BeanC.class, BeanC::new); + context.refresh(); + + assertFalse(context.getBeanFactory().containsSingleton("annotationConfigApplicationContextTests.BeanA")); assertSame(context.getBean(BeanB.class), context.getBean(BeanA.class).b); assertSame(context.getBean(BeanC.class), context.getBean(BeanA.class).c); assertSame(context, context.getBean(BeanB.class).applicationContext); @@ -159,6 +182,24 @@ public class AnnotationConfigApplicationContextTests { context.registerBean("b", BeanB.class, BeanB::new); context.registerBean("c", BeanC.class, BeanC::new); context.refresh(); + + assertTrue(context.getBeanFactory().containsSingleton("a")); + assertSame(context.getBean("b", BeanB.class), context.getBean(BeanA.class).b); + assertSame(context.getBean("c"), context.getBean("a", BeanA.class).c); + assertSame(context, context.getBean("b", BeanB.class).applicationContext); + } + + @Test + public void individualNamedBeanWithSupplierAndCustomizer() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.registerBean("a", BeanA.class, + () -> new BeanA(context.getBean(BeanB.class), context.getBean(BeanC.class)), + bd -> bd.setLazyInit(true)); + context.registerBean("b", BeanB.class, BeanB::new); + context.registerBean("c", BeanC.class, BeanC::new); + context.refresh(); + + assertFalse(context.getBeanFactory().containsSingleton("a")); assertSame(context.getBean("b", BeanB.class), context.getBean(BeanA.class).b); assertSame(context.getBean("c"), context.getBean("a", BeanA.class).c); assertSame(context, context.getBean("b", BeanB.class).applicationContext); @@ -171,6 +212,7 @@ public class AnnotationConfigApplicationContextTests { BeanC c = new BeanC(); context.registerBean(BeanA.class, b, c); context.refresh(); + assertSame(b, context.getBean(BeanA.class).b); assertSame(c, context.getBean(BeanA.class).c); assertNull(b.applicationContext); @@ -183,6 +225,7 @@ public class AnnotationConfigApplicationContextTests { BeanC c = new BeanC(); context.registerBean("a", BeanA.class, b, c); context.refresh(); + assertSame(b, context.getBean("a", BeanA.class).b); assertSame(c, context.getBean("a", BeanA.class).c); assertNull(b.applicationContext); @@ -195,6 +238,7 @@ public class AnnotationConfigApplicationContextTests { context.registerBean(BeanA.class, c); context.registerBean(BeanB.class); context.refresh(); + assertSame(context.getBean(BeanB.class), context.getBean(BeanA.class).b); assertSame(c, context.getBean(BeanA.class).c); assertSame(context, context.getBean(BeanB.class).applicationContext); @@ -207,6 +251,7 @@ public class AnnotationConfigApplicationContextTests { context.registerBean("a", BeanA.class, c); context.registerBean("b", BeanB.class); context.refresh(); + assertSame(context.getBean("b", BeanB.class), context.getBean("a", BeanA.class).b); assertSame(c, context.getBean("a", BeanA.class).c); assertSame(context, context.getBean("b", BeanB.class).applicationContext);