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
Referencing a @Bean method in a @Configuration class' @PostConstruct method leads to circular reference #27876
Comments
You may have three ways to solve it:
|
Thanks, @kse-music, but each of those solutions comes with serious drawbacks:
A better example to clarify: in spring-boot < 2.6, the below code simply works, and the test underneath it succeeds. @Configuration
public class AppConf {
private static Integer counter = 0;
public static Integer testBeanFromInit;
@Bean
public Integer getTestBean() {
return ++counter;
}
@PostConstruct
public void init() {
testBeanFromInit = getTestBean();
}
} @SpringBootTest
class DemoApplicationTests {
@Autowired
Integer testBean;
@Test
void contextLoads() {
System.out.println(AppConf.testBeanFromInit);
System.out.println(testBean);
assertEquals("Not the same bean as in the init", testBean, AppConf.testBeanFromInit);
}
} I'm not really looking for a workaround: I simply think the limitations of @configuration's @PostConstruct methods, starting with 2.6.0 should be mentioned somewhere. The release notes do mention "circular references prohibited by default", and that seems to be exactly what's happening: getTestBean() needs AppConf to be fully constructed, while inside the @PostConstruct-method it is still in the process of being constructed. But: it's called PostConstruct, so construction should already be finished, and I should be able to get the testBean. Hence the confusion, and the need to clearly specify the expected behaviour. |
oops,may be your issue is similar to #25443 ,Thank you for @BartRobeyns interpretion |
It's not really the same as #25443: that one is about two beans depending on each other - a true circular dependency, and if I read the ticket correct, it was actually failing in 2.5. |
Added to triage queue as there is some change in behavior, possibly requiring a small documentation update/clarification? |
Note that the issue also occurs if post-construct is accessing auto-wired field injected with @Configuration
public class AppConf {
@Autowired
WebApp webApp;
@PostConstruct
public void init() {
webApp.startApp();
}
@Bean
public WebApp getWebApp() {
return new WebApp();
}
}
public class WebApp {
private boolean started;
public void startApp() {
// do start stuff
System.out.println("Running startApp");
started = true;
}
public boolean isStarted() {
return started;
}
}
@SpringBootTest(classes = AppConf.class)
class DemoApplicationTest {
@Autowired
WebApp webApp;
@Test
void contextLoads() {
Assertions.assertTrue(webApp.isStarted());
}
} |
The change in behavior is in Spring Boot: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes#circular-references-prohibited-by-default. Though we can certainly document that accessing local |
Note that in Spring Boot this specific case was not reported as a circular reference (normally you'd get a warning in the logs, I believe).
That's why I felt the release note doesn't apply here: it didn't use to be a circular dependency.
Or I'm wrong about the warning? :)
|
Hi @BartRobeyns, It could well be that my interpretation is incorrect, and since you feel certain it is a change in behavior in Spring Framework (and not in Spring Boot) we will certainly want to confirm the previous behavior compared to the current behavior in order to decide what documentation to change/improve. |
Thanks for considering this Sam. I didn't state anything about the source of the change (whether it's Spring Boot or Spring Framework) - and don't really have a clue about it either. I'm only looking at it from the Spring Boot perspective, and noticed the change in behaviour between Spring Boot 2.5 and 2.6. |
Spring Boot does not log a warning in case of a circular reference that the context can handle. It does provide a failure analysis if the context can't handle it with additional details. That doesn't apply to the case you've described.
They do IMO. This circular reference, like others, could be solved transparently by the context (so you'd not know about it) and we made it apparent in Spring Boot 2.6.x by explicitly preventing them by default. |
@snicoll that clarifies the release notes for me, thanks. |
@BartRobeyns the issue is still open so it means we are still considering documenting something. |
After upgrading to spring-boot 2.6.x, it is no longer possible to access a bean in the
@PostConstruct
method of the@Configuration
class where it was defined. This did work before (tested with 2.1.x, 2.5.6).Example code that will result in a
BeanCurrentlyInCreationException
, printing "Application Failed to start", with "The dependencies of some of the beans in the application context form a cycle:"You can get a full example at https://github.com/BartRobeyns/boot26ConfigPostConstruct (spring-initializer project with only the
@Configuration
class above added) that fails to build.Changing the spring-boot version to 2.5.x will allow the application to build and run.
Note that I'm totally fine with this behavior (
@PostConstruct
in a@Configuration
class seems pretty weird to me), but the documentation of@PostConstruct
does state that the... so it's easy to expect the sample above to work. An explicit mention that you shouldn't access
@Bean
methods from the@Configuration
class itself would clear that up.The text was updated successfully, but these errors were encountered: