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 { | ||||
| 				beanCreation.end(); | ||||
| 				if (!isCacheBeanMetadata()) { | ||||
| 					clearMergedBeanDefinition(beanName); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | @ -583,7 +586,6 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp | |||
| 		Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ? | ||||
| 				new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch}); | ||||
| 
 | ||||
| 
 | ||||
| 		// Attempt to predict the bean type | ||||
| 		Class<?> predictedType = null; | ||||
| 
 | ||||
|  | @ -1409,7 +1411,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp | |||
| 
 | ||||
| 				// Cache the merged bean definition for the time being | ||||
| 				// (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); | ||||
| 				} | ||||
| 			} | ||||
|  | @ -1433,6 +1435,9 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp | |||
| 				mbd.factoryMethodReturnType = previous.factoryMethodReturnType; | ||||
| 				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"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  | @ -53,7 +53,6 @@ public class LookupAnnotationTests { | |||
| 	@Test | ||||
| 	public void testWithoutConstructorArg() { | ||||
| 		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean"); | ||||
| 		assertThat(bean).isNotNull(); | ||||
| 		Object expected = bean.get(); | ||||
| 		assertThat(expected.getClass()).isEqualTo(TestBean.class); | ||||
| 		assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean); | ||||
|  | @ -62,7 +61,6 @@ public class LookupAnnotationTests { | |||
| 	@Test | ||||
| 	public void testWithOverloadedArg() { | ||||
| 		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean"); | ||||
| 		assertThat(bean).isNotNull(); | ||||
| 		TestBean expected = bean.get("haha"); | ||||
| 		assertThat(expected.getClass()).isEqualTo(TestBean.class); | ||||
| 		assertThat(expected.getName()).isEqualTo("haha"); | ||||
|  | @ -72,7 +70,6 @@ public class LookupAnnotationTests { | |||
| 	@Test | ||||
| 	public void testWithOneConstructorArg() { | ||||
| 		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean"); | ||||
| 		assertThat(bean).isNotNull(); | ||||
| 		TestBean expected = bean.getOneArgument("haha"); | ||||
| 		assertThat(expected.getClass()).isEqualTo(TestBean.class); | ||||
| 		assertThat(expected.getName()).isEqualTo("haha"); | ||||
|  | @ -82,7 +79,6 @@ public class LookupAnnotationTests { | |||
| 	@Test | ||||
| 	public void testWithTwoConstructorArg() { | ||||
| 		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean"); | ||||
| 		assertThat(bean).isNotNull(); | ||||
| 		TestBean expected = bean.getTwoArguments("haha", 72); | ||||
| 		assertThat(expected.getClass()).isEqualTo(TestBean.class); | ||||
| 		assertThat(expected.getName()).isEqualTo("haha"); | ||||
|  | @ -93,7 +89,6 @@ public class LookupAnnotationTests { | |||
| 	@Test | ||||
| 	public void testWithThreeArgsShouldFail() { | ||||
| 		AbstractBean bean = (AbstractBean) beanFactory.getBean("abstractBean"); | ||||
| 		assertThat(bean).isNotNull(); | ||||
| 		assertThatExceptionOfType(AbstractMethodError.class).as("TestBean has no three arg constructor").isThrownBy(() -> | ||||
| 				bean.getThreeArguments("name", 1, 2)); | ||||
| 		assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean); | ||||
|  | @ -102,7 +97,6 @@ public class LookupAnnotationTests { | |||
| 	@Test | ||||
| 	public void testWithEarlyInjection() { | ||||
| 		AbstractBean bean = beanFactory.getBean("beanConsumer", BeanConsumer.class).abstractBean; | ||||
| 		assertThat(bean).isNotNull(); | ||||
| 		Object expected = bean.get(); | ||||
| 		assertThat(expected.getClass()).isEqualTo(TestBean.class); | ||||
| 		assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean); | ||||
|  | @ -115,7 +109,6 @@ public class LookupAnnotationTests { | |||
| 		beanFactory.registerBeanDefinition("testBean", tbd); | ||||
| 
 | ||||
| 		AbstractBean bean = beanFactory.getBean("beanConsumer", BeanConsumer.class).abstractBean; | ||||
| 		assertThat(bean).isNotNull(); | ||||
| 		Object expected = bean.get(); | ||||
| 		assertThat(expected).isNull(); | ||||
| 		assertThat(beanFactory.getBean(BeanConsumer.class).abstractBean).isSameAs(bean); | ||||
|  | @ -128,7 +121,36 @@ public class LookupAnnotationTests { | |||
| 		beanFactory.registerBeanDefinition("floatStore", new RootBeanDefinition(FloatStore.class)); | ||||
| 
 | ||||
| 		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(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