Support [package-]private init/destroy methods in AOT mode
Prior to this commit, private (and non-visible package-private) init/destroy methods were not supported in AOT mode. The reason is that such methods are tracked using their fully-qualified method names, and the AOT support for init/destroy methods previously did not take fully-qualified method names into account. In addition, the invocation order of init/destroy methods differed vastly between standard JVM mode and AOT mode. This commit addresses these issues in the following ways. - AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(), DisposableBeanAdapter.determineDestroyMethod(), and BeanDefinitionPropertiesCodeGenerator.addInitDestroyHint() now parse fully-qualified method names to locate the correct init/destroy methods. - AbstractAutowireCapableBeanFactory and DisposableBeanAdapter delegate to a new MethodDescriptor record which encapsulates the parsing of fully-qualified method names; however, BeanDefinitionPropertiesCodeGenerator duplicates this logic since it resides in a different package, and we do not currently want to make MethodDescriptor public. - Init/destroy methods detected via annotations (such as @PostConstruct and @PreDestroy) are now invoked prior to init/destroy methods that are explicitly configured by name or convention. This aligns with the invocation order in standard JVM mode; however, InitializingBean#afterPropertiesSet() and DisposableBean#destroy() are still invoked before annotated init/destroy methods in AOT mode which differs from standard JVM mode. - Unit and integration tests have been updated to test the revised behavior. Closes gh-30692
This commit is contained in:
@@ -70,8 +70,8 @@ class InitDestroyAnnotationBeanPostProcessorTests {
|
||||
beanDefinition.setDestroyMethodNames("customDestroyMethod");
|
||||
processAheadOfTime(beanDefinition);
|
||||
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition();
|
||||
assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly("customInitMethod", "initMethod");
|
||||
assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly("customDestroyMethod", "destroyMethod");
|
||||
assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly("initMethod", "customInitMethod");
|
||||
assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly("destroyMethod", "customDestroyMethod");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -129,16 +129,16 @@ class InitDestroyAnnotationBeanPostProcessorTests {
|
||||
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition();
|
||||
assertSoftly(softly -> {
|
||||
softly.assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly(
|
||||
"afterPropertiesSet",
|
||||
"customInit",
|
||||
CustomAnnotatedPrivateInitDestroyBean.class.getName() + ".privateInit", // fully-qualified private method
|
||||
CustomAnnotatedPrivateSameNameInitDestroyBean.class.getName() + ".privateInit" // fully-qualified private method
|
||||
CustomAnnotatedPrivateSameNameInitDestroyBean.class.getName() + ".privateInit", // fully-qualified private method
|
||||
"afterPropertiesSet",
|
||||
"customInit"
|
||||
);
|
||||
softly.assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly(
|
||||
"destroy",
|
||||
"customDestroy",
|
||||
CustomAnnotatedPrivateSameNameInitDestroyBean.class.getName() + ".privateDestroy", // fully-qualified private method
|
||||
CustomAnnotatedPrivateInitDestroyBean.class.getName() + ".privateDestroy" // fully-qualified private method
|
||||
CustomAnnotatedPrivateInitDestroyBean.class.getName() + ".privateDestroy", // fully-qualified private method
|
||||
"destroy",
|
||||
"customDestroy"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -376,6 +376,9 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
||||
@Nested
|
||||
class InitDestroyMethodTests {
|
||||
|
||||
private final String privateInitMethod = InitDestroyBean.class.getName() + ".privateInit";
|
||||
private final String privateDestroyMethod = InitDestroyBean.class.getName() + ".privateDestroy";
|
||||
|
||||
@BeforeEach
|
||||
void setTargetType() {
|
||||
beanDefinition.setTargetType(InitDestroyBean.class);
|
||||
@@ -393,11 +396,18 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
||||
assertHasMethodInvokeHints(InitDestroyBean.class, "init");
|
||||
}
|
||||
|
||||
@Test
|
||||
void privateInitMethod() {
|
||||
beanDefinition.setInitMethodName(privateInitMethod);
|
||||
compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).containsExactly(privateInitMethod));
|
||||
assertHasMethodInvokeHints(InitDestroyBean.class, "privateInit");
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipleInitMethods() {
|
||||
beanDefinition.setInitMethodNames("init", "init2");
|
||||
compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).containsExactly("init", "init2"));
|
||||
assertHasMethodInvokeHints(InitDestroyBean.class, "init", "init2");
|
||||
beanDefinition.setInitMethodNames("init", privateInitMethod);
|
||||
compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).containsExactly("init", privateInitMethod));
|
||||
assertHasMethodInvokeHints(InitDestroyBean.class, "init", "privateInit");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -412,11 +422,18 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
||||
assertHasMethodInvokeHints(InitDestroyBean.class, "destroy");
|
||||
}
|
||||
|
||||
@Test
|
||||
void privateDestroyMethod() {
|
||||
beanDefinition.setDestroyMethodName(privateDestroyMethod);
|
||||
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly(privateDestroyMethod));
|
||||
assertHasMethodInvokeHints(InitDestroyBean.class, "privateDestroy");
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipleDestroyMethods() {
|
||||
beanDefinition.setDestroyMethodNames("destroy", "destroy2");
|
||||
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("destroy", "destroy2"));
|
||||
assertHasMethodInvokeHints(InitDestroyBean.class, "destroy", "destroy2");
|
||||
beanDefinition.setDestroyMethodNames("destroy", privateDestroyMethod);
|
||||
compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("destroy", privateDestroyMethod));
|
||||
assertHasMethodInvokeHints(InitDestroyBean.class, "destroy", "privateDestroy");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -461,13 +478,15 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
||||
void init() {
|
||||
}
|
||||
|
||||
void init2() {
|
||||
@SuppressWarnings("unused")
|
||||
private void privateInit() {
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
}
|
||||
|
||||
void destroy2() {
|
||||
@SuppressWarnings("unused")
|
||||
private void privateDestroy() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user