From 23bf5f563bd4757500aac0cf94e91be61c1e159a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 28 Mar 2013 21:44:07 +0100 Subject: [PATCH] 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 --- .../config/AutowireCapableBeanFactory.java | 12 +++++++++- .../AbstractAutowireCapableBeanFactory.java | 4 ++++ .../support/DisposableBeanAdapter.java | 22 ++++++++++++++++--- .../DefaultListableBeanFactoryTests.java | 19 +++++++++++++++- 4 files changed, 52 insertions(+), 5 deletions(-) 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 e71eb1a8991..003ab7e2ce3 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 09faf0c3b25..b589b1a6c6b 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 6a498344a92..672c8924311 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 73c2ab592a6..9197e0083e5 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();