We can't call @Validated
bean's method on application shutdown because defaultValidator
bean is destroyed first even though we are referring it.
Sample Application
MyBean
with@Validated
depends ondefaultValidator
implicitly throughMethodValidationInterceptor
MyService
depends onMyBean
MyService
takes a while to destroy and it callsMyBean
at last- But the call fails due to
BeanCreationNotAllowedException
package com.example.demo;
import javax.annotation.PreDestroy;
import org.springframework.beans.factory.BeanCreationNotAllowedException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Service
static class MyService {
private final MyBean myBean;
MyService(MyBean myBean) {
this.myBean = myBean;
}
@PreDestroy
void destroy() {
System.out.println("MyService.destroy");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
myBean.method();
} catch (BeanCreationNotAllowedException ex) {
// This is thrown because defaultValidator has already been closed.
ex.printStackTrace();
}
}
}
@Component
@Validated
// This is a workaround for this issue:
// @DependsOn("defaultValidator")
static class MyBean {
void method() {
System.out.println("MyBean.method");
}
@PreDestroy
void destroy() {
System.out.println("MyBean.destroy");
}
}
}
See the following link for the complete demo app code: https://github.com/uphy/20231010_BeanCreationNotAllowedExceptionDemo
Workaround
- Add
@DependsOn("defaultValidator")
toMyBean
- Add
@ConfigurationProperties
annotation toMyBean
(ref https://github.com/spring-projects/spring-boot/commit/f60f3cb38eeb40f6863d86b8ef91fa395c513a82) - Use
MethodValidationExcludeFilter
to exclude method validation fromMyBean
Environment
- Spring Boot 2.7.6
- Java 11
Comment From: vishalsingh2972
@uphy @sbrannen can you assign this to me if it's still open ?
Comment From: uphy
@vishalsingh2972 Thank you! I am not authorized to assign, so I will wait for @sbrannen's response.
Comment From: snicoll
@vishalsingh2972 thanks for the offer but we haven't triaged the issue yet so nobody can really work on it really. Except if you've found what the issue was?
Comment From: snicoll
@uphy I can't reproduce the issue that you have described. Both with framework 5.3 and 6.x, the shutdown is initiated with the sleep there and it ends up with:
2023-10-05 16:22:08.799 INFO 22703 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 0.558 seconds (JVM running for 0.744)
MyService.destroy
MyBean.method
MyBean.destroy
Going forward, please share a sample that we can run rather than code in text that we'll have to copy/paste anyway in a project to be able to investigate. You can do that by attaching a zip to the issue or sharing a link to a GitHub repository with the code.
I am going to close this but we can reopen if you manage to reproduce. Please provide more instructions in that case.
Comment From: uphy
@snicoll Thank you for checking. I could reproduce the issue again with latest environment.
See the following link for the complete demo project: https://github.com/uphy/20231010_BeanCreationNotAllowedExceptionDemo
Could you reopen this issue?
Comment From: snicoll
Thanks, I've reproduced it now. This is similar to #22526
Comment From: jhoeller
As of 6.2, we leniently tolerate late retrieval of existing instances during destroySingletons()
, making late bean interactions possible during destroy method invocations even for retrievals from an on-demand supplier or async worker etc. After all, such late interactions were already possible for bean instances that got stored directly, and late retrieval was possible for beans without destroy methods (even if they were part of a depends-on arrangement in the other direction), so we may also tolerate interactions when retrieved on demand now: typically for validators and transaction managers, late-bound and/or potentially late-qualified.