Polish InitDestroyAnnotationBeanPostProcessor internals, etc.

This commit is contained in:
Sam Brannen 2023-06-21 13:44:01 +02:00
parent 93218a06ba
commit 2fd83aa764
5 changed files with 85 additions and 65 deletions

View File

@ -82,6 +82,7 @@ dependencies {
api("jakarta.websocket:jakarta.websocket-api:2.1.0") api("jakarta.websocket:jakarta.websocket-api:2.1.0")
api("jakarta.websocket:jakarta.websocket-client-api:2.1.0") api("jakarta.websocket:jakarta.websocket-client-api:2.1.0")
api("jakarta.xml.bind:jakarta.xml.bind-api:3.0.1") api("jakarta.xml.bind:jakarta.xml.bind-api:3.0.1")
api("javax.annotation:javax.annotation-api:1.3.2")
api("javax.cache:cache-api:1.1.1") api("javax.cache:cache-api:1.1.1")
api("javax.money:money-api:1.1") api("javax.money:money-api:1.1")
api("jaxen:jaxen:1.2.0") api("jaxen:jaxen:1.2.0")

View File

@ -24,7 +24,6 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
@ -79,6 +78,7 @@ import org.springframework.util.ReflectionUtils;
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Phillip Webb * @author Phillip Webb
* @author Sam Brannen
* @since 2.5 * @since 2.5
* @see #setInitAnnotationType * @see #setInitAnnotationType
* @see #setDestroyAnnotationType * @see #setDestroyAnnotationType
@ -153,7 +153,7 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
@Override @Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
findInjectionMetadata(beanDefinition, beanType); findLifecycleMetadata(beanDefinition, beanType);
} }
@Override @Override
@ -161,7 +161,7 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition(); RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();
beanDefinition.resolveDestroyMethodIfNecessary(); beanDefinition.resolveDestroyMethodIfNecessary();
LifecycleMetadata metadata = findInjectionMetadata(beanDefinition, registeredBean.getBeanClass()); LifecycleMetadata metadata = findLifecycleMetadata(beanDefinition, registeredBean.getBeanClass());
if (!CollectionUtils.isEmpty(metadata.initMethods)) { if (!CollectionUtils.isEmpty(metadata.initMethods)) {
String[] initMethodNames = safeMerge(beanDefinition.getInitMethodNames(), metadata.initMethods); String[] initMethodNames = safeMerge(beanDefinition.getInitMethodNames(), metadata.initMethods);
beanDefinition.setInitMethodNames(initMethodNames); beanDefinition.setInitMethodNames(initMethodNames);
@ -173,14 +173,14 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
return null; return null;
} }
private LifecycleMetadata findInjectionMetadata(RootBeanDefinition beanDefinition, Class<?> beanType) { private LifecycleMetadata findLifecycleMetadata(RootBeanDefinition beanDefinition, Class<?> beanType) {
LifecycleMetadata metadata = findLifecycleMetadata(beanType); LifecycleMetadata metadata = findLifecycleMetadata(beanType);
metadata.checkInitDestroyMethods(beanDefinition); metadata.checkInitDestroyMethods(beanDefinition);
return metadata; return metadata;
} }
private String[] safeMerge(@Nullable String[] existingNames, Collection<LifecycleElement> detectedElements) { private static String[] safeMerge(@Nullable String[] existingNames, Collection<LifecycleMethod> detectedMethods) {
Stream<String> detectedNames = detectedElements.stream().map(LifecycleElement::getIdentifier); Stream<String> detectedNames = detectedMethods.stream().map(LifecycleMethod::getIdentifier);
Stream<String> mergedNames = (existingNames != null ? Stream<String> mergedNames = (existingNames != null ?
Stream.concat(Stream.of(existingNames), detectedNames) : detectedNames); Stream.concat(Stream.of(existingNames), detectedNames) : detectedNames);
return mergedNames.distinct().toArray(String[]::new); return mergedNames.distinct().toArray(String[]::new);
@ -217,12 +217,14 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.warn(msg, ex.getTargetException()); logger.warn(msg, ex.getTargetException());
} }
else { else if (logger.isWarnEnabled()) {
logger.warn(msg + ": " + ex.getTargetException()); logger.warn(msg + ": " + ex.getTargetException());
} }
} }
catch (Throwable ex) { catch (Throwable ex) {
logger.warn("Failed to invoke destroy method on bean with name '" + beanName + "'", ex); if (logger.isWarnEnabled()) {
logger.warn("Failed to invoke destroy method on bean with name '" + beanName + "'", ex);
}
} }
} }
@ -253,28 +255,27 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
} }
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) { private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) { if (!AnnotationUtils.isCandidateClass(clazz, List.of(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata; return this.emptyLifecycleMetadata;
} }
List<LifecycleElement> initMethods = new ArrayList<>(); List<LifecycleMethod> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>(); List<LifecycleMethod> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz; Class<?> targetClass = clazz;
do { do {
final List<LifecycleElement> currInitMethods = new ArrayList<>(); final List<LifecycleMethod> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>(); final List<LifecycleMethod> currDestroyMethods = new ArrayList<>();
ReflectionUtils.doWithLocalMethods(targetClass, method -> { ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) { if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method); currInitMethods.add(new LifecycleMethod(method));
currInitMethods.add(element);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method); logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
} }
} }
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) { if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method)); currDestroyMethods.add(new LifecycleMethod(method));
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method); logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
} }
@ -312,18 +313,18 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
private final Class<?> targetClass; private final Class<?> targetClass;
private final Collection<LifecycleElement> initMethods; private final Collection<LifecycleMethod> initMethods;
private final Collection<LifecycleElement> destroyMethods; private final Collection<LifecycleMethod> destroyMethods;
@Nullable @Nullable
private volatile Set<LifecycleElement> checkedInitMethods; private volatile Set<LifecycleMethod> checkedInitMethods;
@Nullable @Nullable
private volatile Set<LifecycleElement> checkedDestroyMethods; private volatile Set<LifecycleMethod> checkedDestroyMethods;
public LifecycleMetadata(Class<?> targetClass, Collection<LifecycleElement> initMethods, public LifecycleMetadata(Class<?> targetClass, Collection<LifecycleMethod> initMethods,
Collection<LifecycleElement> destroyMethods) { Collection<LifecycleMethod> destroyMethods) {
this.targetClass = targetClass; this.targetClass = targetClass;
this.initMethods = initMethods; this.initMethods = initMethods;
@ -331,23 +332,23 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
} }
public void checkInitDestroyMethods(RootBeanDefinition beanDefinition) { public void checkInitDestroyMethods(RootBeanDefinition beanDefinition) {
Set<LifecycleElement> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size()); Set<LifecycleMethod> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size());
for (LifecycleElement element : this.initMethods) { for (LifecycleMethod lifecycleMethod : this.initMethods) {
String methodIdentifier = element.getIdentifier(); String methodIdentifier = lifecycleMethod.getIdentifier();
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) { if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
beanDefinition.registerExternallyManagedInitMethod(methodIdentifier); beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
checkedInitMethods.add(element); checkedInitMethods.add(lifecycleMethod);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Registered init method on class [" + this.targetClass.getName() + "]: " + methodIdentifier); logger.trace("Registered init method on class [" + this.targetClass.getName() + "]: " + methodIdentifier);
} }
} }
} }
Set<LifecycleElement> checkedDestroyMethods = new LinkedHashSet<>(this.destroyMethods.size()); Set<LifecycleMethod> checkedDestroyMethods = new LinkedHashSet<>(this.destroyMethods.size());
for (LifecycleElement element : this.destroyMethods) { for (LifecycleMethod lifecycleMethod : this.destroyMethods) {
String methodIdentifier = element.getIdentifier(); String methodIdentifier = lifecycleMethod.getIdentifier();
if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) { if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) {
beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier); beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier);
checkedDestroyMethods.add(element); checkedDestroyMethods.add(lifecycleMethod);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Registered destroy method on class [" + this.targetClass.getName() + "]: " + methodIdentifier); logger.trace("Registered destroy method on class [" + this.targetClass.getName() + "]: " + methodIdentifier);
} }
@ -358,36 +359,36 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
} }
public void invokeInitMethods(Object target, String beanName) throws Throwable { public void invokeInitMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods; Collection<LifecycleMethod> checkedInitMethods = this.checkedInitMethods;
Collection<LifecycleElement> initMethodsToIterate = Collection<LifecycleMethod> initMethodsToIterate =
(checkedInitMethods != null ? checkedInitMethods : this.initMethods); (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
if (!initMethodsToIterate.isEmpty()) { if (!initMethodsToIterate.isEmpty()) {
for (LifecycleElement element : initMethodsToIterate) { for (LifecycleMethod lifecycleMethod : initMethodsToIterate) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod()); logger.trace("Invoking init method on bean '" + beanName + "': " + lifecycleMethod.getMethod());
} }
element.invoke(target); lifecycleMethod.invoke(target);
} }
} }
} }
public void invokeDestroyMethods(Object target, String beanName) throws Throwable { public void invokeDestroyMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> checkedDestroyMethods = this.checkedDestroyMethods; Collection<LifecycleMethod> checkedDestroyMethods = this.checkedDestroyMethods;
Collection<LifecycleElement> destroyMethodsToUse = Collection<LifecycleMethod> destroyMethodsToUse =
(checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods); (checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods);
if (!destroyMethodsToUse.isEmpty()) { if (!destroyMethodsToUse.isEmpty()) {
for (LifecycleElement element : destroyMethodsToUse) { for (LifecycleMethod lifecycleMethod : destroyMethodsToUse) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Invoking destroy method on bean '" + beanName + "': " + element.getMethod()); logger.trace("Invoking destroy method on bean '" + beanName + "': " + lifecycleMethod.getMethod());
} }
element.invoke(target); lifecycleMethod.invoke(target);
} }
} }
} }
public boolean hasDestroyMethods() { public boolean hasDestroyMethods() {
Collection<LifecycleElement> checkedDestroyMethods = this.checkedDestroyMethods; Collection<LifecycleMethod> checkedDestroyMethods = this.checkedDestroyMethods;
Collection<LifecycleElement> destroyMethodsToUse = Collection<LifecycleMethod> destroyMethodsToUse =
(checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods); (checkedDestroyMethods != null ? checkedDestroyMethods : this.destroyMethods);
return !destroyMethodsToUse.isEmpty(); return !destroyMethodsToUse.isEmpty();
} }
@ -395,17 +396,17 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
/** /**
* Class representing injection information about an annotated method. * Class representing an annotated init or destroy method.
*/ */
private static class LifecycleElement { private static class LifecycleMethod {
private final Method method; private final Method method;
private final String identifier; private final String identifier;
public LifecycleElement(Method method) { public LifecycleMethod(Method method) {
if (method.getParameterCount() != 0) { if (method.getParameterCount() != 0) {
throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method); throw new IllegalStateException("Lifecycle annotation requires a no-arg method: " + method);
} }
this.method = method; this.method = method;
this.identifier = (Modifier.isPrivate(method.getModifiers()) ? this.identifier = (Modifier.isPrivate(method.getModifiers()) ?
@ -422,18 +423,13 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB
public void invoke(Object target) throws Throwable { public void invoke(Object target) throws Throwable {
ReflectionUtils.makeAccessible(this.method); ReflectionUtils.makeAccessible(this.method);
this.method.invoke(target, (Object[]) null); this.method.invoke(target);
} }
@Override @Override
public boolean equals(@Nullable Object other) { public boolean equals(@Nullable Object other) {
if (this == other) { return (this == other || (other instanceof LifecycleMethod that &&
return true; this.identifier.equals(that.identifier)));
}
if (!(other instanceof LifecycleElement otherElement)) {
return false;
}
return (this.identifier.equals(otherElement.identifier));
} }
@Override @Override

View File

@ -1832,9 +1832,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
/** /**
* Invoke the specified custom init method on the given bean. * Invoke the specified custom init method on the given bean.
* Called by invokeInitMethods. * <p>Called by {@link #invokeInitMethods(String, Object, RootBeanDefinition)}.
* <p>Can be overridden in subclasses for custom resolution of init * <p>Can be overridden in subclasses for custom resolution of init methods
* methods with arguments. * with arguments.
* @see #invokeInitMethods * @see #invokeInitMethods
*/ */
protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd, String initMethodName) protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd, String initMethodName)

View File

@ -36,6 +36,7 @@ dependencies {
testImplementation("org.apache.commons:commons-pool2") testImplementation("org.apache.commons:commons-pool2")
testImplementation("org.awaitility:awaitility") testImplementation("org.awaitility:awaitility")
testImplementation("jakarta.inject:jakarta.inject-tck") testImplementation("jakarta.inject:jakarta.inject-tck")
testImplementation("javax.annotation:javax.annotation-api")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core") testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
testRuntimeOnly("jakarta.xml.bind:jakarta.xml.bind-api") testRuntimeOnly("jakarta.xml.bind:jakarta.xml.bind-api")
testRuntimeOnly("org.glassfish:jakarta.el") testRuntimeOnly("org.glassfish:jakarta.el")

View File

@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
@ -80,7 +81,7 @@ class InitDestroyMethodLifecycleTests {
} }
@Test @Test
void jsr250Annotations() { void jakartaAnnotations() {
Class<?> beanClass = CustomAnnotatedInitDestroyBean.class; Class<?> beanClass = CustomAnnotatedInitDestroyBean.class;
DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", "customDestroy"); DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", "customDestroy");
CustomAnnotatedInitDestroyBean bean = beanFactory.getBean(CustomAnnotatedInitDestroyBean.class); CustomAnnotatedInitDestroyBean bean = beanFactory.getBean(CustomAnnotatedInitDestroyBean.class);
@ -90,7 +91,7 @@ class InitDestroyMethodLifecycleTests {
} }
@Test @Test
void jsr250AnnotationsWithShadowedMethods() { void jakartaAnnotationsWithShadowedMethods() {
Class<?> beanClass = CustomAnnotatedInitDestroyWithShadowedMethodsBean.class; Class<?> beanClass = CustomAnnotatedInitDestroyWithShadowedMethodsBean.class;
DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", "customDestroy"); DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", "customDestroy");
CustomAnnotatedInitDestroyWithShadowedMethodsBean bean = beanFactory.getBean(CustomAnnotatedInitDestroyWithShadowedMethodsBean.class); CustomAnnotatedInitDestroyWithShadowedMethodsBean bean = beanFactory.getBean(CustomAnnotatedInitDestroyWithShadowedMethodsBean.class);
@ -100,7 +101,7 @@ class InitDestroyMethodLifecycleTests {
} }
@Test @Test
void jsr250AnnotationsWithCustomPrivateInitDestroyMethods() { void jakartaAnnotationsWithCustomPrivateInitDestroyMethods() {
Class<?> beanClass = CustomAnnotatedPrivateInitDestroyBean.class; Class<?> beanClass = CustomAnnotatedPrivateInitDestroyBean.class;
DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit1", "customDestroy1"); DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit1", "customDestroy1");
CustomAnnotatedPrivateInitDestroyBean bean = beanFactory.getBean(CustomAnnotatedPrivateInitDestroyBean.class); CustomAnnotatedPrivateInitDestroyBean bean = beanFactory.getBean(CustomAnnotatedPrivateInitDestroyBean.class);
@ -110,13 +111,25 @@ class InitDestroyMethodLifecycleTests {
} }
@Test @Test
void jsr250AnnotationsWithCustomSameMethodNames() { void jakartaAnnotationsCustomPrivateInitDestroyMethodsWithTheSameMethodNames() {
Class<?> beanClass = CustomAnnotatedPrivateSameNameInitDestroyBean.class; Class<?> beanClass = CustomAnnotatedPrivateSameNameInitDestroyBean.class;
DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit1", "customDestroy1"); DefaultListableBeanFactory beanFactory = createBeanFactoryAndRegisterBean(beanClass, "customInit", "customDestroy");
CustomAnnotatedPrivateSameNameInitDestroyBean bean = beanFactory.getBean(CustomAnnotatedPrivateSameNameInitDestroyBean.class); CustomAnnotatedPrivateSameNameInitDestroyBean bean = beanFactory.getBean(CustomAnnotatedPrivateSameNameInitDestroyBean.class);
assertThat(bean.initMethods).as("init-methods").containsExactly("@PostConstruct.privateCustomInit1", "@PostConstruct.sameNameCustomInit1", "afterPropertiesSet");
assertThat(bean.initMethods).as("init-methods").containsExactly(
"@PostConstruct.privateCustomInit1",
"@PostConstruct.sameNameCustomInit1",
"afterPropertiesSet",
"customInit"
);
beanFactory.destroySingletons(); beanFactory.destroySingletons();
assertThat(bean.destroyMethods).as("destroy-methods").containsExactly("@PreDestroy.sameNameCustomDestroy1", "@PreDestroy.privateCustomDestroy1", "destroy"); assertThat(bean.destroyMethods).as("destroy-methods").containsExactly(
"@PreDestroy.sameNameCustomDestroy1",
"@PreDestroy.privateCustomDestroy1",
"destroy",
"customDestroy"
);
} }
@Test @Test
@ -134,10 +147,19 @@ class InitDestroyMethodLifecycleTests {
String initMethodName, String destroyMethodName) { String initMethodName, String destroyMethodName) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
// Configure and register an InitDestroyAnnotationBeanPostProcessor as
// done in AnnotationConfigUtils.registerAnnotationConfigProcessors()
// for an ApplicatonContext.
InitDestroyAnnotationBeanPostProcessor initDestroyBpp = new InitDestroyAnnotationBeanPostProcessor();
initDestroyBpp.setInitAnnotationType(javax.annotation.PostConstruct.class);
initDestroyBpp.setDestroyAnnotationType(javax.annotation.PreDestroy.class);
beanFactory.addBeanPostProcessor(initDestroyBpp);
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setInitMethodName(initMethodName); beanDefinition.setInitMethodName(initMethodName);
beanDefinition.setDestroyMethodName(destroyMethodName); beanDefinition.setDestroyMethodName(destroyMethodName);
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
beanFactory.registerBeanDefinition("lifecycleTestBean", beanDefinition); beanFactory.registerBeanDefinition("lifecycleTestBean", beanDefinition);
return beanFactory; return beanFactory;
} }