diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java index e71eb1a899..003ab7e2ce 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -302,6 +302,16 @@ public interface AutowireCapableBeanFactory extends BeanFactory { Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException; + /** + * Destroy the given bean instance (typically coming from {@link #createBean}), + * applying the {@link org.springframework.beans.factory.DisposableBean} contract as well as + * registered {@link DestructionAwareBeanPostProcessor DestructionAwareBeanPostProcessors}. + *

Any exception that arises during destruction should be caught + * and logged instead of propagated to the caller of this method. + * @param existingBean the bean instance to destroy + */ + void destroyBean(Object existingBean); + /** * Resolve the specified dependency against the beans defined in this factory. * @param descriptor the descriptor for the dependency diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 09faf0c3b2..b589b1a6c6 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -417,6 +417,10 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac return result; } + public void destroyBean(Object existingBean) { + new DisposableBeanAdapter(existingBean, getBeanPostProcessors(), getAccessControlContext()).destroy(); + } + //--------------------------------------------------------------------- // Implementation of relevant AbstractBeanFactory template methods diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java index 6a498344a9..672c892431 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java @@ -85,14 +85,14 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { private final boolean nonPublicAccessAllowed; + private final AccessControlContext acc; + private String destroyMethodName; private transient Method destroyMethod; private List beanPostProcessors; - private final AccessControlContext acc; - /** * Create a new DisposableBeanAdapter for the given bean. @@ -138,6 +138,22 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { this.beanPostProcessors = filterPostProcessors(postProcessors); } + /** + * Create a new DisposableBeanAdapter for the given bean. + * @param bean the bean instance (never {@code null}) + * @param postProcessors the List of BeanPostProcessors + * (potentially DestructionAwareBeanPostProcessor), if any + */ + public DisposableBeanAdapter(Object bean, List postProcessors, AccessControlContext acc) { + Assert.notNull(bean, "Disposable bean must not be null"); + this.bean = bean; + this.beanName = null; + this.invokeDisposableBean = (this.bean instanceof DisposableBean); + this.nonPublicAccessAllowed = true; + this.acc = acc; + this.beanPostProcessors = filterPostProcessors(postProcessors); + } + /** * Create a new DisposableBeanAdapter for the given bean. */ @@ -149,9 +165,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { this.beanName = beanName; this.invokeDisposableBean = invokeDisposableBean; this.nonPublicAccessAllowed = nonPublicAccessAllowed; + this.acc = null; this.destroyMethodName = destroyMethodName; this.beanPostProcessors = postProcessors; - this.acc = null; } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java index 73c2ab592a..9197e0083e 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java @@ -32,7 +32,6 @@ import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.Set; - import javax.security.auth.Subject; import org.apache.commons.logging.Log; @@ -41,6 +40,7 @@ import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; + import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.NotWritablePropertyException; @@ -1552,6 +1552,23 @@ public class DefaultListableBeanFactoryTests { assertNull(tb.getSpouse()); } + @Test + public void testCreateBean() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + TestBean tb = lbf.createBean(TestBean.class); + assertSame(lbf, tb.getBeanFactory()); + lbf.destroyBean(tb); + } + + @Test + public void testCreateBeanWithDisposableBean() { + DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); + DerivedTestBean tb = lbf.createBean(DerivedTestBean.class); + assertSame(lbf, tb.getBeanFactory()); + lbf.destroyBean(tb); + assertTrue(tb.wasDestroyed()); + } + @Test public void testConfigureBean() { DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();