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