-
Notifications
You must be signed in to change notification settings - Fork 40.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@ConfigurationProperties does not work on @Bean methods in auto-configuration classes when metadata caching is disabled on the bean factory #18440
Comments
@arnesacnussem Thanks for the sample. I ran the test in |
found out it happens when using certain jvm i run into this bug when updating another project from 2.2.0.M1 to 2.2.0.M6,the old version of Spring boot work fine with dcevm. I also tried |
Thanks for the additional information. The failure's occurring because the The failure can be reproduced on vanilla OpenJDK using an package com.example.demo;
import java.util.Locale;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.MessageSource;
@SpringBootConfiguration
@ImportAutoConfiguration(MessageSourceAutoConfiguration.class)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(DemoApplication.class);
application.addInitializers(new ApplicationContextInitializer() {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.getBeanFactory().setCacheBeanMetadata(false);
}
});
MessageSource messageSource = application.run(args).getBean(MessageSource.class);
messageSource.getMessage("content", null, Locale.getDefault());
}
} Further investigation is required to determine if this is a Spring Boot problem or a Spring Framework problem. |
Here are a couple of Spring Framework tests that illustrate the difference in behaviour: package example;
import static org.assertj.core.api.Assertions.assertThat;
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.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
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 {
}
} |
The Framework tests behave the same way with 5.1 and 5.2, but from a Boot perspective this appears to be a regression. The test above fails with Spring Boot 2.2.0 snapshots but passes with Spring Boot 2.1.8. I think the root cause of that is the fix for #16220 where we moved from our own reflective search for the factory method to retrieving it from the bean definition. This relied on some changes in Framework that were tracked by spring-projects/spring-framework#22420. I'm not sure if we need a change in Framework or if Boot needs a fallback when the factory method isn't available. |
@jhoeller could you guide us here please? |
@philwebb since the initial refactoring came from your side, are you aware of any gaps there? I'm not quite aware what kind of factory methods Boot would have found that we're still not exposing there... |
@jhoeller I don't think this is a result of the initial refactoring as Framework behaves the same way in 5.1 and 5.2. It's a regression in Boot as, in Boot 2.2, we're leaning more heavily on Framework and are now being affected by the difference in behaviour when caching is and is not enabled.
Having investigated further and written up the above, I'm now of the opinion that this is a bug in Framework. |
I've opened spring-projects/spring-framework#23795 so that we can hopefully revert the main code changes in b240c81 in the future. |
Spring Boot version 2.2.0.M6
change the value of
spring.messages.basename
inapplication.properties
does not make any differencedemo.zip
In this demo,the test
com.example.demo.DemoApplicationTests#contextLoads
will always fail.Make a breakpoint at
resolveCodeWithoutArguments:151, org.springframework.context.support.ResourceBundleMessageSource#resolveCodeWithoutArguments
The
getBasenameSet()
will always return a set which only contain one element: "messages"But if eval the
getResourceBundle("msg", locale)
at that point,it will return the correct thing.Also
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration.ResourceBundleCondition#getResources
returns the correct thing.The text was updated successfully, but these errors were encountered: