Browse Source

Update InitDestroyAnnotationBeanPostProcessor AOT support

Update `InitDestroyAnnotationBeanPostProcessor` so that it provides
AOT contributions via the `BeanRegistrationAotProcessor` interface.

See gh-28414
pull/28422/head
Phillip Webb 3 years ago
parent
commit
7664a54c93
  1. 22
      spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java
  2. 84
      spring-beans/src/test/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessorTests.java

22
spring-beans/src/main/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessor.java

@ -39,10 +39,13 @@ import org.apache.commons.logging.LogFactory; @@ -39,10 +39,13 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
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.generator.AotContributingBeanPostProcessor;
import org.springframework.beans.factory.generator.BeanInstantiationContribution;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
@ -77,13 +80,15 @@ import org.springframework.util.ReflectionUtils; @@ -77,13 +80,15 @@ import org.springframework.util.ReflectionUtils;
*
* @author Juergen Hoeller
* @author Stephane Nicoll
* @author Phillip Webb
* @since 2.5
* @see #setInitAnnotationType
* @see #setDestroyAnnotationType
*/
@SuppressWarnings("serial")
public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor,
MergedBeanDefinitionPostProcessor, AotContributingBeanPostProcessor, PriorityOrdered, Serializable {
MergedBeanDefinitionPostProcessor, AotContributingBeanPostProcessor, BeanRegistrationAotProcessor,
PriorityOrdered, Serializable {
private final transient LifecycleMetadata emptyLifecycleMetadata =
new LifecycleMetadata(Object.class, Collections.emptyList(), Collections.emptyList()) {
@ -170,6 +175,21 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB @@ -170,6 +175,21 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
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) {
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
metadata.checkConfigMembers(beanDefinition);

84
spring-beans/src/test/java/org/springframework/beans/factory/annotation/InitDestroyAnnotationBeanPostProcessorTests.java

@ -19,6 +19,8 @@ package org.springframework.beans.factory.annotation; @@ -19,6 +19,8 @@ package org.springframework.beans.factory.annotation;
import org.junit.jupiter.api.Test;
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.testfixture.beans.factory.generator.lifecycle.Destroy;
import org.springframework.beans.testfixture.beans.factory.generator.lifecycle.Init;
@ -34,13 +36,16 @@ import static org.mockito.Mockito.verifyNoInteractions; @@ -34,13 +36,16 @@ import static org.mockito.Mockito.verifyNoInteractions;
* Tests for {@link InitDestroyAnnotationBeanPostProcessor}.
*
* @author Stephane Nicoll
* @author Phillip Webb
*/
class InitDestroyAnnotationBeanPostProcessorTests {
private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@Test
void contributeWithNoCallbackDoesNotMutateRootBeanDefinition() {
RootBeanDefinition beanDefinition = mock(RootBeanDefinition.class);
assertThat(createAotContributingBeanPostProcessor().contribute(
assertThat(createAotBeanPostProcessor().contribute(
beanDefinition, String.class, "test")).isNull();
verifyNoInteractions(beanDefinition);
}
@ -87,15 +92,80 @@ class InitDestroyAnnotationBeanPostProcessorTests { @@ -87,15 +92,80 @@ class InitDestroyAnnotationBeanPostProcessorTests {
@Nullable
private BeanInstantiationContribution createContribution(RootBeanDefinition beanDefinition) {
InitDestroyAnnotationBeanPostProcessor bpp = createAotContributingBeanPostProcessor();
InitDestroyAnnotationBeanPostProcessor bpp = createAotBeanPostProcessor();
return bpp.contribute(beanDefinition, beanDefinition.getResolvableType().toClass(), "test");
}
private InitDestroyAnnotationBeanPostProcessor createAotContributingBeanPostProcessor() {
InitDestroyAnnotationBeanPostProcessor bpp = new InitDestroyAnnotationBeanPostProcessor();
bpp.setInitAnnotationType(Init.class);
bpp.setDestroyAnnotationType(Destroy.class);
return bpp;
@Test
void processAheadOfTimeWhenNoCallbackDoesNotMutateRootBeanDefinition() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
processAheadOfTime(beanDefinition);
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…
Cancel
Save