Update InitDestroyAnnotationBeanPostProcessor AOT support
Update `InitDestroyAnnotationBeanPostProcessor` so that it provides AOT contributions via the `BeanRegistrationAotProcessor` interface. See gh-28414
This commit is contained in:
parent
77c5a6f18d
commit
7664a54c93
|
|
@ -39,10 +39,13 @@ import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
|
||||||
|
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
|
||||||
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
|
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
|
||||||
import org.springframework.beans.factory.generator.AotContributingBeanPostProcessor;
|
import org.springframework.beans.factory.generator.AotContributingBeanPostProcessor;
|
||||||
import org.springframework.beans.factory.generator.BeanInstantiationContribution;
|
import org.springframework.beans.factory.generator.BeanInstantiationContribution;
|
||||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||||
|
import org.springframework.beans.factory.support.RegisteredBean;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.PriorityOrdered;
|
import org.springframework.core.PriorityOrdered;
|
||||||
|
|
@ -77,13 +80,15 @@ import org.springframework.util.ReflectionUtils;
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Phillip Webb
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
* @see #setInitAnnotationType
|
* @see #setInitAnnotationType
|
||||||
* @see #setDestroyAnnotationType
|
* @see #setDestroyAnnotationType
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor,
|
public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor,
|
||||||
MergedBeanDefinitionPostProcessor, AotContributingBeanPostProcessor, PriorityOrdered, Serializable {
|
MergedBeanDefinitionPostProcessor, AotContributingBeanPostProcessor, BeanRegistrationAotProcessor,
|
||||||
|
PriorityOrdered, Serializable {
|
||||||
|
|
||||||
private final transient LifecycleMetadata emptyLifecycleMetadata =
|
private final transient LifecycleMetadata emptyLifecycleMetadata =
|
||||||
new LifecycleMetadata(Object.class, Collections.emptyList(), Collections.emptyList()) {
|
new LifecycleMetadata(Object.class, Collections.emptyList(), Collections.emptyList()) {
|
||||||
|
|
@ -170,6 +175,21 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
|
||||||
|
RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();
|
||||||
|
LifecycleMetadata metadata = findInjectionMetadata(beanDefinition, registeredBean.getBeanClass());
|
||||||
|
if (!CollectionUtils.isEmpty(metadata.initMethods)) {
|
||||||
|
String[] initMethodNames = safeMerge(beanDefinition.getInitMethodNames(), metadata.initMethods);
|
||||||
|
beanDefinition.setInitMethodNames(initMethodNames);
|
||||||
|
}
|
||||||
|
if (!CollectionUtils.isEmpty(metadata.destroyMethods)) {
|
||||||
|
String[] destroyMethodNames = safeMerge(beanDefinition.getDestroyMethodNames(), metadata.destroyMethods);
|
||||||
|
beanDefinition.setDestroyMethodNames(destroyMethodNames);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private LifecycleMetadata findInjectionMetadata(RootBeanDefinition beanDefinition, Class<?> beanType) {
|
private LifecycleMetadata findInjectionMetadata(RootBeanDefinition beanDefinition, Class<?> beanType) {
|
||||||
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
|
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
|
||||||
metadata.checkConfigMembers(beanDefinition);
|
metadata.checkConfigMembers(beanDefinition);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ package org.springframework.beans.factory.annotation;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.beans.factory.generator.BeanInstantiationContribution;
|
import org.springframework.beans.factory.generator.BeanInstantiationContribution;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.RegisteredBean;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.beans.testfixture.beans.factory.generator.lifecycle.Destroy;
|
import org.springframework.beans.testfixture.beans.factory.generator.lifecycle.Destroy;
|
||||||
import org.springframework.beans.testfixture.beans.factory.generator.lifecycle.Init;
|
import org.springframework.beans.testfixture.beans.factory.generator.lifecycle.Init;
|
||||||
|
|
@ -34,13 +36,16 @@ import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
* Tests for {@link InitDestroyAnnotationBeanPostProcessor}.
|
* Tests for {@link InitDestroyAnnotationBeanPostProcessor}.
|
||||||
*
|
*
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
|
* @author Phillip Webb
|
||||||
*/
|
*/
|
||||||
class InitDestroyAnnotationBeanPostProcessorTests {
|
class InitDestroyAnnotationBeanPostProcessorTests {
|
||||||
|
|
||||||
|
private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void contributeWithNoCallbackDoesNotMutateRootBeanDefinition() {
|
void contributeWithNoCallbackDoesNotMutateRootBeanDefinition() {
|
||||||
RootBeanDefinition beanDefinition = mock(RootBeanDefinition.class);
|
RootBeanDefinition beanDefinition = mock(RootBeanDefinition.class);
|
||||||
assertThat(createAotContributingBeanPostProcessor().contribute(
|
assertThat(createAotBeanPostProcessor().contribute(
|
||||||
beanDefinition, String.class, "test")).isNull();
|
beanDefinition, String.class, "test")).isNull();
|
||||||
verifyNoInteractions(beanDefinition);
|
verifyNoInteractions(beanDefinition);
|
||||||
}
|
}
|
||||||
|
|
@ -87,15 +92,80 @@ class InitDestroyAnnotationBeanPostProcessorTests {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private BeanInstantiationContribution createContribution(RootBeanDefinition beanDefinition) {
|
private BeanInstantiationContribution createContribution(RootBeanDefinition beanDefinition) {
|
||||||
InitDestroyAnnotationBeanPostProcessor bpp = createAotContributingBeanPostProcessor();
|
InitDestroyAnnotationBeanPostProcessor bpp = createAotBeanPostProcessor();
|
||||||
return bpp.contribute(beanDefinition, beanDefinition.getResolvableType().toClass(), "test");
|
return bpp.contribute(beanDefinition, beanDefinition.getResolvableType().toClass(), "test");
|
||||||
}
|
}
|
||||||
|
|
||||||
private InitDestroyAnnotationBeanPostProcessor createAotContributingBeanPostProcessor() {
|
@Test
|
||||||
InitDestroyAnnotationBeanPostProcessor bpp = new InitDestroyAnnotationBeanPostProcessor();
|
void processAheadOfTimeWhenNoCallbackDoesNotMutateRootBeanDefinition() {
|
||||||
bpp.setInitAnnotationType(Init.class);
|
RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
|
||||||
bpp.setDestroyAnnotationType(Destroy.class);
|
processAheadOfTime(beanDefinition);
|
||||||
return bpp;
|
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition();
|
||||||
|
assertThat(mergedBeanDefinition.getInitMethodNames()).isNull();
|
||||||
|
assertThat(mergedBeanDefinition.getDestroyMethodNames()).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processAheadOfTimeWhenHasInitDestroyAnnotationsAddsMethodNames() {
|
||||||
|
RootBeanDefinition beanDefinition = new RootBeanDefinition(InitDestroyBean.class);
|
||||||
|
processAheadOfTime(beanDefinition);
|
||||||
|
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition();
|
||||||
|
assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly("initMethod");
|
||||||
|
assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly("destroyMethod");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processAheadOfTimeWhenHasInitDestroyAnnotationsAndCustomDefinedMethodNamesAddsMethodNames() {
|
||||||
|
RootBeanDefinition beanDefinition = new RootBeanDefinition(InitDestroyBean.class);
|
||||||
|
beanDefinition.setInitMethodName("customInitMethod");
|
||||||
|
beanDefinition.setDestroyMethodNames("customDestroyMethod");
|
||||||
|
processAheadOfTime(beanDefinition);
|
||||||
|
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition();
|
||||||
|
assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly("customInitMethod", "initMethod");
|
||||||
|
assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly("customDestroyMethod", "destroyMethod");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processAheadOfTimeWhenHasInitDestroyAnnotationsAndOverlappingCustomDefinedMethodNamesFiltersDuplicates() {
|
||||||
|
RootBeanDefinition beanDefinition = new RootBeanDefinition(InitDestroyBean.class);
|
||||||
|
beanDefinition.setInitMethodName("initMethod");
|
||||||
|
beanDefinition.setDestroyMethodNames("destroyMethod");
|
||||||
|
processAheadOfTime(beanDefinition);
|
||||||
|
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition();
|
||||||
|
assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly("initMethod");
|
||||||
|
assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly("destroyMethod");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processAheadOfTimeWhenHasMultipleInitDestroyAnnotationsAddsAllMethodNames() {
|
||||||
|
RootBeanDefinition beanDefinition = new RootBeanDefinition(MultiInitDestroyBean.class);
|
||||||
|
processAheadOfTime(beanDefinition);
|
||||||
|
RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition();
|
||||||
|
assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly("initMethod", "anotherInitMethod");
|
||||||
|
assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly("anotherDestroyMethod", "destroyMethod");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processAheadOfTime(RootBeanDefinition beanDefinition) {
|
||||||
|
RegisteredBean registeredBean = registerBean(beanDefinition);
|
||||||
|
assertThat(createAotBeanPostProcessor().processAheadOfTime(registeredBean)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegisteredBean registerBean(RootBeanDefinition beanDefinition) {
|
||||||
|
String beanName = "test";
|
||||||
|
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
|
||||||
|
RegisteredBean registeredBean = RegisteredBean.of(this.beanFactory, beanName);
|
||||||
|
return registeredBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RootBeanDefinition getMergedBeanDefinition() {
|
||||||
|
return (RootBeanDefinition) this.beanFactory.getMergedBeanDefinition("test");
|
||||||
|
}
|
||||||
|
|
||||||
|
private InitDestroyAnnotationBeanPostProcessor createAotBeanPostProcessor() {
|
||||||
|
InitDestroyAnnotationBeanPostProcessor beanPostProcessor = new InitDestroyAnnotationBeanPostProcessor();
|
||||||
|
beanPostProcessor.setInitAnnotationType(Init.class);
|
||||||
|
beanPostProcessor.setDestroyAnnotationType(Destroy.class);
|
||||||
|
return beanPostProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue