diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java index 5a16754b70..90e7080fd9 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -37,6 +37,7 @@ import org.springframework.aop.RawTargetAccess; import org.springframework.aop.TargetSource; import org.springframework.aop.support.AopUtils; import org.springframework.cglib.core.CodeGenerationException; +import org.springframework.cglib.core.SpringNamingPolicy; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.CallbackFilter; import org.springframework.cglib.proxy.Dispatcher; @@ -45,7 +46,7 @@ import org.springframework.cglib.proxy.Factory; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import org.springframework.cglib.proxy.NoOp; -import org.springframework.cglib.transform.impl.MemorySafeUndeclaredThrowableStrategy; +import org.springframework.cglib.transform.impl.UndeclaredThrowableStrategy; import org.springframework.core.SmartClassLoader; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -183,19 +184,19 @@ class CglibAopProxy implements AopProxy, Serializable { } } enhancer.setSuperclass(proxySuperClass); - enhancer.setStrategy(new MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class)); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); + enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); + enhancer.setStrategy(new UndeclaredThrowableStrategy(UndeclaredThrowableException.class)); Callback[] callbacks = getCallbacks(rootClass); Class[] types = new Class[callbacks.length]; - for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } - - enhancer.setCallbackTypes(types); + // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); + enhancer.setCallbackTypes(types); // Generate the proxy class and create a proxy instance. return createProxyClassAndInstance(enhancer, callbacks); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java index a70d634807..4b2c763fc6 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -23,7 +23,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.BeanFactory; - +import org.springframework.cglib.core.SpringNamingPolicy; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.CallbackFilter; import org.springframework.cglib.proxy.Enhancer; @@ -107,6 +107,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt public Object instantiate(Constructor ctor, Object[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.beanDefinition.getBeanClass()); + enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setCallbackFilter(new CallbackFilterImpl()); enhancer.setCallbacks(new Callback[] { NoOp.INSTANCE, @@ -114,9 +115,7 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt new ReplaceOverrideMethodInterceptor() }); - return (ctor == null) ? - enhancer.create() : - enhancer.create(ctor.getParameterTypes(), args); + return (ctor != null ? enhancer.create(ctor.getParameterTypes(), args) : enhancer.create()); } 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 a9fd647795..fc378c5a8d 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -34,6 +34,7 @@ import org.springframework.beans.factory.support.SimpleInstantiationStrategy; import org.springframework.cglib.core.ClassGenerator; import org.springframework.cglib.core.Constants; import org.springframework.cglib.core.DefaultGeneratorStrategy; +import org.springframework.cglib.core.SpringNamingPolicy; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.CallbackFilter; import org.springframework.cglib.proxy.Enhancer; @@ -67,6 +68,8 @@ class ConfigurationClassEnhancer { private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS); + private static final DefaultGeneratorStrategy GENERATOR_STRATEGY = new BeanFactoryAwareGeneratorStrategy(); + private static final String BEAN_FACTORY_FIELD = "$$beanFactory"; private static final Log logger = LogFactory.getLog(ConfigurationClassEnhancer.class); @@ -105,22 +108,10 @@ class ConfigurationClassEnhancer { enhancer.setSuperclass(superclass); enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class}); enhancer.setUseFactory(false); + enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); + enhancer.setStrategy(GENERATOR_STRATEGY); enhancer.setCallbackFilter(CALLBACK_FILTER); enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes()); - enhancer.setStrategy(new DefaultGeneratorStrategy() { - @Override - protected ClassGenerator transform(ClassGenerator cg) throws Exception { - ClassEmitterTransformer transformer = new ClassEmitterTransformer() { - @Override - public void end_class() { - declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, - Type.getType(BeanFactory.class), null); - super.end_class(); - } - }; - return new TransformingClassGenerator(cg, transformer); - } - }); return enhancer; } @@ -200,37 +191,27 @@ 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 + * Custom extension of CGLIB's DefaultGeneratorStrategy, introducing a {@link BeanFactory} field. */ - private static class DisposableBeanMethodInterceptor implements MethodInterceptor, ConditionalCallback { + private static class BeanFactoryAwareGeneratorStrategy extends DefaultGeneratorStrategy { @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()); + protected ClassGenerator transform(ClassGenerator cg) throws Exception { + ClassEmitterTransformer transformer = new ClassEmitterTransformer() { + @Override + public void end_class() { + declare_field(Constants.ACC_PUBLIC, BEAN_FACTORY_FIELD, Type.getType(BeanFactory.class), null); + super.end_class(); + } + }; + return new TransformingClassGenerator(cg, transformer); } } /** - * Intercepts the invocation of any - * {@link BeanFactoryAware#setBeanFactory(BeanFactory)} on {@code @Configuration} - * class instances for the purpose of recording the {@link BeanFactory}. + * Intercepts the invocation of any {@link BeanFactoryAware#setBeanFactory(BeanFactory)} on + * {@code @Configuration} class instances for the purpose of recording the {@link BeanFactory}. * @see EnhancedConfiguration */ private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback { @@ -387,6 +368,7 @@ class ConfigurationClassEnhancer { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(fbClass); enhancer.setUseFactory(false); + enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { @@ -404,7 +386,8 @@ class ConfigurationClassEnhancer { Assert.state(field != null, "Unable to find generated bean factory field"); Object beanFactory = ReflectionUtils.getField(field, enhancedConfigInstance); Assert.state(beanFactory != null, "BeanFactory has not been injected into @Configuration class"); - Assert.state(beanFactory instanceof ConfigurableBeanFactory, "Injected BeanFactory is not a ConfigurableBeanFactory"); + Assert.state(beanFactory instanceof ConfigurableBeanFactory, + "Injected BeanFactory is not a ConfigurableBeanFactory"); return (ConfigurableBeanFactory) beanFactory; } @@ -414,4 +397,32 @@ 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-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java b/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java new file mode 100644 index 0000000000..839f36f8b3 --- /dev/null +++ b/spring-core/src/main/java/org/springframework/cglib/core/SpringNamingPolicy.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2014 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.cglib.core; + +/** + * Custom extension of CGLIB's {@link DefaultNamingPolicy}, modifying + * the tag in generated class names from "ByCGLIB" to "BySpringCGLIB". + * + *

This is primarily designed to avoid clashes between a regular CGLIB + * version (used by some other library) and Spring's embedded variant, + * in case the same class happens to get proxied for different purposes. + * + * @author Juergen Hoeller + * @since 3.2.8 + */ +public class SpringNamingPolicy extends DefaultNamingPolicy { + + public static final SpringNamingPolicy INSTANCE = new SpringNamingPolicy(); + + @Override + protected String getTag() { + return "BySpringCGLIB"; + } + +} diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/impl/MemorySafeUndeclaredThrowableStrategy.java b/spring-core/src/main/java/org/springframework/cglib/transform/impl/MemorySafeUndeclaredThrowableStrategy.java deleted file mode 100644 index 18c926c3de..0000000000 --- a/spring-core/src/main/java/org/springframework/cglib/transform/impl/MemorySafeUndeclaredThrowableStrategy.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - * 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.cglib.transform.impl; - -import org.springframework.cglib.core.ClassGenerator; -import org.springframework.cglib.core.DefaultGeneratorStrategy; -import org.springframework.cglib.core.TypeUtils; -import org.springframework.cglib.transform.ClassTransformer; -import org.springframework.cglib.transform.MethodFilter; -import org.springframework.cglib.transform.MethodFilterTransformer; -import org.springframework.cglib.transform.TransformingClassGenerator; - -/** - * Memory safe variant of {@link UndeclaredThrowableStrategy} ported from the latest - * as yet unreleased cglib code. - */ -public class MemorySafeUndeclaredThrowableStrategy extends DefaultGeneratorStrategy { - - private static final MethodFilter TRANSFORM_FILTER = new MethodFilter() { - public boolean accept(int access, String name, String desc, String signature, - String[] exceptions) { - return !TypeUtils.isPrivate(access) && name.indexOf('$') < 0; - } - }; - - - private Class wrapper; - - - public MemorySafeUndeclaredThrowableStrategy(Class wrapper) { - this.wrapper = wrapper; - } - - - protected ClassGenerator transform(ClassGenerator cg) throws Exception { - ClassTransformer tr = new UndeclaredThrowableTransformer(wrapper); - tr = new MethodFilterTransformer(TRANSFORM_FILTER, tr); - return new TransformingClassGenerator(cg, tr); - } -} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java index 0384261b82..f4022992f7 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -29,6 +29,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.target.EmptyTargetSource; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.cglib.core.SpringNamingPolicy; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.Factory; @@ -72,16 +73,15 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder { public static final String MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME = "mvcUriComponentsContributor"; - private static final CompositeUriComponentsContributor defaultUriComponentsContributor; + private static final Log logger = LogFactory.getLog(MvcUriComponentsBuilder.class); + + private static final ObjenesisStd objenesis = new ObjenesisStd(true); private static final PathMatcher pathMatcher = new AntPathMatcher(); private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); - private static final ObjenesisStd objenesis = new ObjenesisStd(true); - - private static final Log logger = LogFactory.getLog(MvcUriComponentsBuilder.class); - + private static final CompositeUriComponentsContributor defaultUriComponentsContributor; static { defaultUriComponentsContributor = new CompositeUriComponentsContributor( @@ -341,7 +341,8 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder { else { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(type); - enhancer.setInterfaces(new Class[]{MethodInvocationInfo.class}); + enhancer.setInterfaces(new Class[] {MethodInvocationInfo.class}); + enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setCallbackType(org.springframework.cglib.proxy.MethodInterceptor.class); Factory factory = (Factory) objenesis.newInstance(enhancer.createClass()); factory.setCallbacks(new Callback[] {interceptor});