Added "destroyBean(Object)" method to AutowireCapableBeanFactory

Driven by the need for implementing Bean Validation 1.1's "releaseInstance" method in SpringConstraintValidatorFactory, as a direct counterpart to the use of AutowireCapableBeanFactory's "createBean(Class)" in "getInstance".

Issue: SPR-8199
This commit is contained in:
Juergen Hoeller 2013-03-28 21:44:07 +01:00
parent 9f9dc34b53
commit 23bf5f563b
4 changed files with 52 additions and 5 deletions

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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) Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException; 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}.
* <p>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. * Resolve the specified dependency against the beans defined in this factory.
* @param descriptor the descriptor for the dependency * @param descriptor the descriptor for the dependency

View File

@ -417,6 +417,10 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
return result; return result;
} }
public void destroyBean(Object existingBean) {
new DisposableBeanAdapter(existingBean, getBeanPostProcessors(), getAccessControlContext()).destroy();
}
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Implementation of relevant AbstractBeanFactory template methods // Implementation of relevant AbstractBeanFactory template methods

View File

@ -85,14 +85,14 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
private final boolean nonPublicAccessAllowed; private final boolean nonPublicAccessAllowed;
private final AccessControlContext acc;
private String destroyMethodName; private String destroyMethodName;
private transient Method destroyMethod; private transient Method destroyMethod;
private List<DestructionAwareBeanPostProcessor> beanPostProcessors; private List<DestructionAwareBeanPostProcessor> beanPostProcessors;
private final AccessControlContext acc;
/** /**
* Create a new DisposableBeanAdapter for the given bean. * Create a new DisposableBeanAdapter for the given bean.
@ -138,6 +138,22 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
this.beanPostProcessors = filterPostProcessors(postProcessors); 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<BeanPostProcessor> 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. * Create a new DisposableBeanAdapter for the given bean.
*/ */
@ -149,9 +165,9 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable {
this.beanName = beanName; this.beanName = beanName;
this.invokeDisposableBean = invokeDisposableBean; this.invokeDisposableBean = invokeDisposableBean;
this.nonPublicAccessAllowed = nonPublicAccessAllowed; this.nonPublicAccessAllowed = nonPublicAccessAllowed;
this.acc = null;
this.destroyMethodName = destroyMethodName; this.destroyMethodName = destroyMethodName;
this.beanPostProcessors = postProcessors; this.beanPostProcessors = postProcessors;
this.acc = null;
} }

View File

@ -32,7 +32,6 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import javax.security.auth.Subject; import javax.security.auth.Subject;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -41,6 +40,7 @@ import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.NotWritablePropertyException; import org.springframework.beans.NotWritablePropertyException;
@ -1552,6 +1552,23 @@ public class DefaultListableBeanFactoryTests {
assertNull(tb.getSpouse()); 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 @Test
public void testConfigureBean() { public void testConfigureBean() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(); DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();