Retain metadata during bean creation even with cacheBeanMetadata=false
Closes gh-23795 Closes gh-25749
This commit is contained in:
		
							parent
							
								
									c942c04aa0
								
							
						
					
					
						commit
						c3e18bc173
					
				| 
						 | 
					@ -383,6 +383,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			finally {
 | 
								finally {
 | 
				
			||||||
				beanCreation.end();
 | 
									beanCreation.end();
 | 
				
			||||||
 | 
									if (!isCacheBeanMetadata()) {
 | 
				
			||||||
 | 
										clearMergedBeanDefinition(beanName);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -583,7 +586,6 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
 | 
				
			||||||
		Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
 | 
							Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
 | 
				
			||||||
				new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
 | 
									new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Attempt to predict the bean type
 | 
							// Attempt to predict the bean type
 | 
				
			||||||
		Class<?> predictedType = null;
 | 
							Class<?> predictedType = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1409,7 +1411,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Cache the merged bean definition for the time being
 | 
									// Cache the merged bean definition for the time being
 | 
				
			||||||
				// (it might still get re-merged later on in order to pick up metadata changes)
 | 
									// (it might still get re-merged later on in order to pick up metadata changes)
 | 
				
			||||||
				if (containingBd == null && isCacheBeanMetadata()) {
 | 
									if (containingBd == null && (isCacheBeanMetadata() || isBeanEligibleForMetadataCaching(beanName))) {
 | 
				
			||||||
					this.mergedBeanDefinitions.put(beanName, mbd);
 | 
										this.mergedBeanDefinitions.put(beanName, mbd);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -1433,6 +1435,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
 | 
				
			||||||
				mbd.factoryMethodReturnType = previous.factoryMethodReturnType;
 | 
									mbd.factoryMethodReturnType = previous.factoryMethodReturnType;
 | 
				
			||||||
				mbd.factoryMethodToIntrospect = previous.factoryMethodToIntrospect;
 | 
									mbd.factoryMethodToIntrospect = previous.factoryMethodToIntrospect;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if (previous.hasMethodOverrides()) {
 | 
				
			||||||
 | 
									mbd.setMethodOverrides(new MethodOverrides(previous.getMethodOverrides()));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright 2002-2021 the original author or authors.
 | 
					 * Copyright 2002-2023 the original author or authors.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 * you may not use this file except in compliance with the License.
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
| 
						 | 
					@ -53,7 +53,6 @@ public class LookupAnnotationTests {
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	public void testWithoutConstructorArg() {
 | 
						public void testWithoutConstructorArg() {
 | 
				
			||||||
		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
 | 
							AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
 | 
				
			||||||
		assertThat(bean).isNotNull();
 | 
					 | 
				
			||||||
		Object expected = bean.get();
 | 
							Object expected = bean.get();
 | 
				
			||||||
		assertThat(expected.getClass()).isEqualTo(TestBean.class);
 | 
							assertThat(expected.getClass()).isEqualTo(TestBean.class);
 | 
				
			||||||
		assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
 | 
							assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
 | 
				
			||||||
| 
						 | 
					@ -62,7 +61,6 @@ public class LookupAnnotationTests {
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	public void testWithOverloadedArg() {
 | 
						public void testWithOverloadedArg() {
 | 
				
			||||||
		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
 | 
							AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
 | 
				
			||||||
		assertThat(bean).isNotNull();
 | 
					 | 
				
			||||||
		TestBean expected = bean.get("haha");
 | 
							TestBean expected = bean.get("haha");
 | 
				
			||||||
		assertThat(expected.getClass()).isEqualTo(TestBean.class);
 | 
							assertThat(expected.getClass()).isEqualTo(TestBean.class);
 | 
				
			||||||
		assertThat(expected.getName()).isEqualTo("haha");
 | 
							assertThat(expected.getName()).isEqualTo("haha");
 | 
				
			||||||
| 
						 | 
					@ -72,7 +70,6 @@ public class LookupAnnotationTests {
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	public void testWithOneConstructorArg() {
 | 
						public void testWithOneConstructorArg() {
 | 
				
			||||||
		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
 | 
							AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
 | 
				
			||||||
		assertThat(bean).isNotNull();
 | 
					 | 
				
			||||||
		TestBean expected = bean.getOneArgument("haha");
 | 
							TestBean expected = bean.getOneArgument("haha");
 | 
				
			||||||
		assertThat(expected.getClass()).isEqualTo(TestBean.class);
 | 
							assertThat(expected.getClass()).isEqualTo(TestBean.class);
 | 
				
			||||||
		assertThat(expected.getName()).isEqualTo("haha");
 | 
							assertThat(expected.getName()).isEqualTo("haha");
 | 
				
			||||||
| 
						 | 
					@ -82,7 +79,6 @@ public class LookupAnnotationTests {
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	public void testWithTwoConstructorArg() {
 | 
						public void testWithTwoConstructorArg() {
 | 
				
			||||||
		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
 | 
							AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
 | 
				
			||||||
		assertThat(bean).isNotNull();
 | 
					 | 
				
			||||||
		TestBean expected = bean.getTwoArguments("haha", 72);
 | 
							TestBean expected = bean.getTwoArguments("haha", 72);
 | 
				
			||||||
		assertThat(expected.getClass()).isEqualTo(TestBean.class);
 | 
							assertThat(expected.getClass()).isEqualTo(TestBean.class);
 | 
				
			||||||
		assertThat(expected.getName()).isEqualTo("haha");
 | 
							assertThat(expected.getName()).isEqualTo("haha");
 | 
				
			||||||
| 
						 | 
					@ -93,7 +89,6 @@ public class LookupAnnotationTests {
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	public void testWithThreeArgsShouldFail() {
 | 
						public void testWithThreeArgsShouldFail() {
 | 
				
			||||||
		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
 | 
							AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean");
 | 
				
			||||||
		assertThat(bean).isNotNull();
 | 
					 | 
				
			||||||
		assertThatExceptionOfType(AbstractMethodError.class).as("TestBean has no three arg constructor").isThrownBy(() ->
 | 
							assertThatExceptionOfType(AbstractMethodError.class).as("TestBean has no three arg constructor").isThrownBy(() ->
 | 
				
			||||||
				bean.getThreeArguments("name", 1, 2));
 | 
									bean.getThreeArguments("name", 1, 2));
 | 
				
			||||||
		assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
 | 
							assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
 | 
				
			||||||
| 
						 | 
					@ -102,7 +97,6 @@ public class LookupAnnotationTests {
 | 
				
			||||||
	@Test
 | 
						@Test
 | 
				
			||||||
	public void testWithEarlyInjection() {
 | 
						public void testWithEarlyInjection() {
 | 
				
			||||||
		AbstractBean bean = beanFactory.getBean("beanConsumer", BeanConsumer.class).abstractBean;
 | 
							AbstractBean bean = beanFactory.getBean("beanConsumer", BeanConsumer.class).abstractBean;
 | 
				
			||||||
		assertThat(bean).isNotNull();
 | 
					 | 
				
			||||||
		Object expected = bean.get();
 | 
							Object expected = bean.get();
 | 
				
			||||||
		assertThat(expected.getClass()).isEqualTo(TestBean.class);
 | 
							assertThat(expected.getClass()).isEqualTo(TestBean.class);
 | 
				
			||||||
		assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
 | 
							assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
 | 
				
			||||||
| 
						 | 
					@ -115,7 +109,6 @@ public class LookupAnnotationTests {
 | 
				
			||||||
		beanFactory.registerBeanDefinition("testBean", tbd);
 | 
							beanFactory.registerBeanDefinition("testBean", tbd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AbstractBean bean = beanFactory.getBean("beanConsumer", BeanConsumer.class).abstractBean;
 | 
							AbstractBean bean = beanFactory.getBean("beanConsumer", BeanConsumer.class).abstractBean;
 | 
				
			||||||
		assertThat(bean).isNotNull();
 | 
					 | 
				
			||||||
		Object expected = bean.get();
 | 
							Object expected = bean.get();
 | 
				
			||||||
		assertThat(expected).isNull();
 | 
							assertThat(expected).isNull();
 | 
				
			||||||
		assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
 | 
							assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean);
 | 
				
			||||||
| 
						 | 
					@ -128,7 +121,36 @@ public class LookupAnnotationTests {
 | 
				
			||||||
		beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
 | 
							beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
 | 
							NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
 | 
				
			||||||
		assertThat(bean).isNotNull();
 | 
							assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
 | 
				
			||||||
 | 
							assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void testSingletonWithoutMetadataCaching() {
 | 
				
			||||||
 | 
							beanFactory.setCacheBeanMetadata(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class));
 | 
				
			||||||
 | 
							beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
 | 
				
			||||||
 | 
							beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
 | 
				
			||||||
 | 
							assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
 | 
				
			||||||
 | 
							assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						public void testPrototypeWithoutMetadataCaching() {
 | 
				
			||||||
 | 
							beanFactory.setCacheBeanMetadata(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							beanFactory.registerBeanDefinition("numberBean", new RootBeanDefinition(NumberBean.class, BeanDefinition.SCOPE_PROTOTYPE, null));
 | 
				
			||||||
 | 
							beanFactory.registerBeanDefinition("doubleStore", new RootBeanDefinition(DoubleStore.class));
 | 
				
			||||||
 | 
							beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NumberBean bean = (NumberBean) beanFactory.getBean("numberBean");
 | 
				
			||||||
 | 
							assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
 | 
				
			||||||
 | 
							assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bean = (NumberBean) beanFactory.getBean("numberBean");
 | 
				
			||||||
		assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
 | 
							assertThat(beanFactory.getBean(DoubleStore.class)).isSameAs(bean.getDoubleStore());
 | 
				
			||||||
		assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
 | 
							assertThat(beanFactory.getBean(FloatStore.class)).isSameAs(bean.getFloatStore());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,93 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * 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.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *      https://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.context.annotation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.lang.annotation.ElementType;
 | 
				
			||||||
 | 
					import java.lang.annotation.Retention;
 | 
				
			||||||
 | 
					import java.lang.annotation.RetentionPolicy;
 | 
				
			||||||
 | 
					import java.lang.annotation.Target;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.config.BeanDefinition;
 | 
				
			||||||
 | 
					import org.springframework.beans.factory.support.RootBeanDefinition;
 | 
				
			||||||
 | 
					import org.springframework.core.type.AnnotationMetadata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.assertj.core.api.Assertions.assertThat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @author Andy Wilkinson
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class FactoryMethodResolutionTests {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void factoryMethodCanBeResolvedWithBeanMetadataCachingEnabled() {
 | 
				
			||||||
 | 
							assertThatFactoryMethodCanBeResolved(true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Test
 | 
				
			||||||
 | 
						void factoryMethodCanBeResolvedWithBeanMetadataCachingDisabled() {
 | 
				
			||||||
 | 
							assertThatFactoryMethodCanBeResolved(false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void assertThatFactoryMethodCanBeResolved(boolean cache) {
 | 
				
			||||||
 | 
							try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
 | 
				
			||||||
 | 
								context.getBeanFactory().setCacheBeanMetadata(cache);
 | 
				
			||||||
 | 
								context.register(ImportSelectorConfiguration.class);
 | 
				
			||||||
 | 
								context.refresh();
 | 
				
			||||||
 | 
								BeanDefinition definition = context.getBeanFactory().getMergedBeanDefinition("exampleBean");
 | 
				
			||||||
 | 
								assertThat(((RootBeanDefinition)definition).getResolvedFactoryMethod()).isNotNull();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Configuration
 | 
				
			||||||
 | 
						@Import(ExampleImportSelector.class)
 | 
				
			||||||
 | 
						static class ImportSelectorConfiguration {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static class ExampleImportSelector implements ImportSelector {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public String[] selectImports(AnnotationMetadata importingClassMetadata) {
 | 
				
			||||||
 | 
								return new String[] { TestConfiguration.class.getName() };
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Configuration
 | 
				
			||||||
 | 
						static class TestConfiguration {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Bean
 | 
				
			||||||
 | 
							@ExampleAnnotation
 | 
				
			||||||
 | 
							public ExampleBean exampleBean() {
 | 
				
			||||||
 | 
								return new ExampleBean();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static class ExampleBean {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Target(ElementType.METHOD)
 | 
				
			||||||
 | 
						@Retention(RetentionPolicy.RUNTIME)
 | 
				
			||||||
 | 
						@interface ExampleAnnotation {
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue