diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java index 031037cab8..2913f7eb60 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassEnhancer.java @@ -27,7 +27,6 @@ import org.springframework.aop.scope.ScopedProxyFactoryBean; import org.springframework.asm.Type; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.support.SimpleInstantiationStrategy; @@ -65,9 +64,9 @@ import org.springframework.util.ReflectionUtils; */ class ConfigurationClassEnhancer { + // The callbacks to use. Note that these callbacks must be stateless. private static final Callback[] CALLBACKS = new Callback[] { new BeanMethodInterceptor(), - new DisposableBeanMethodInterceptor(), new BeanFactoryAwareMethodInterceptor(), NoOp.INSTANCE }; @@ -139,15 +138,13 @@ class ConfigurationClassEnhancer { * Facilitates idempotent behavior for {@link ConfigurationClassEnhancer#enhance(Class)} * through checking to see if candidate classes are already assignable to it, e.g. * have already been enhanced. - *
Also extends {@link DisposableBean} and {@link BeanFactoryAware}, as all - * enhanced {@code @Configuration} classes require access to the {@link BeanFactory} - * that created them and must de-register static CGLIB callbacks on destruction, - * which is handled by the (private) {@code DisposableBeanMethodInterceptor}. + *
Also extends {@link BeanFactoryAware}, as all enhanced {@code @Configuration} + * classes require access to the {@link BeanFactory} that created them. *
Note that this interface is intended for framework-internal use only, however * must remain public in order to allow access to subclasses generated from other * packages (i.e. user code). */ - public interface EnhancedConfiguration extends DisposableBean, BeanFactoryAware { + public interface EnhancedConfiguration extends BeanFactoryAware { } @@ -403,32 +400,4 @@ class ConfigurationClassEnhancer { } } - - /** - * Intercepts the invocation of any {@link DisposableBean#destroy()} on @Configuration - * class instances for the purpose of de-registering CGLIB callbacks. This helps avoid - * garbage collection issues. See SPR-7901. - * @see EnhancedConfiguration - */ - private static class DisposableBeanMethodInterceptor implements MethodInterceptor, ConditionalCallback { - - @Override - public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { - Enhancer.registerStaticCallbacks(obj.getClass(), null); - // Does the actual (non-CGLIB) superclass actually implement DisposableBean? - // If so, call its dispose() method. If not, just exit. - if (DisposableBean.class.isAssignableFrom(obj.getClass().getSuperclass())) { - return proxy.invokeSuper(obj, args); - } - return null; - } - - @Override - public boolean isMatch(Method candidateMethod) { - return candidateMethod.getName().equals("destroy") && - candidateMethod.getParameterTypes().length == 0 && - DisposableBean.class.isAssignableFrom(candidateMethod.getDeclaringClass()); - } - } - } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassCglibCallbackDeregistrationTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassCglibCallbackDeregistrationTests.java deleted file mode 100644 index d77bab5812..0000000000 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassCglibCallbackDeregistrationTests.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2002-2012 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.context.annotation.configuration; - -import org.junit.Test; - -import org.springframework.beans.factory.DisposableBean; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Configuration; - -import static org.hamcrest.CoreMatchers.*; -import static org.junit.Assert.*; - -/** - * Tests ensuring that @Configuration-related CGLIB callbacks are de-registered - * at container shutdown time, allowing for proper garbage collection. See SPR-7901. - * - * @author Chris Beams - */ -public class ConfigurationClassCglibCallbackDeregistrationTests { - - /** - * asserting that the actual callback is deregistered is difficult, - * but we can at least assert that the @Configuration class is enhanced - * to implement DisposableBean. The enhanced implementation of destroy() - * will do the de-registration work. - */ - @Test - public void destroyContext() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class); - Config config = ctx.getBean(Config.class); - assertThat(config, instanceOf(DisposableBean.class)); - ctx.destroy(); - } - - /** - * The DisposableBeanMethodInterceptor in ConfigurationClassEnhancer - * should be careful to invoke any explicit super-implementation of - * DisposableBean#destroy(). - */ - @Test - public void destroyExplicitDisposableBeanConfig() { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(DisposableConfig.class); - DisposableConfig config = ctx.getBean(DisposableConfig.class); - assertThat(config.destroyed, is(false)); - ctx.destroy(); - assertThat("DisposableConfig.destroy() was not invoked", config.destroyed, is(true)); - } - - - @Configuration - static class Config { - } - - - @Configuration - static class DisposableConfig implements DisposableBean { - boolean destroyed = false; - @Override - public void destroy() throws Exception { - this.destroyed = true; - } - } -}