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