From 287045ef7452b92d6f8e64a14b48a9026e0648f7 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 26 Feb 2015 18:34:39 +0100 Subject: [PATCH] Allow for shared Objenesis caching in ObjenesisCglibAopProxy Issue: SPR-12755 --- build.gradle | 1 + .../aop/framework/ObjenesisCglibAopProxy.java | 25 +++++---- .../objenesis/SpringObjenesis.java | 56 +++++++++++++++++++ .../objenesis/package-info.java | 15 +++++ .../annotation/MvcUriComponentsBuilder.java | 7 ++- 5 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 spring-core/src/main/java/org/springframework/objenesis/SpringObjenesis.java create mode 100644 spring-core/src/main/java/org/springframework/objenesis/package-info.java diff --git a/build.gradle b/build.gradle index fd8df7d7b8..b78fefa33c 100644 --- a/build.gradle +++ b/build.gradle @@ -328,6 +328,7 @@ project("spring-core") { jarjar("com.googlecode.jarjar:jarjar:1.3") compile(files(cglibRepackJar)) + compile(files(objenesisRepackJar)) compile("commons-logging:commons-logging:1.2") optional("commons-codec:commons-codec:1.10") optional("org.aspectj:aspectjweaver:${aspectjVersion}") diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/ObjenesisCglibAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/ObjenesisCglibAopProxy.java index ee71e87e98..95e59b34bb 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/ObjenesisCglibAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/ObjenesisCglibAopProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 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. @@ -22,14 +22,17 @@ import org.apache.commons.logging.LogFactory; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.Factory; +import org.springframework.objenesis.Objenesis; import org.springframework.objenesis.ObjenesisException; import org.springframework.objenesis.ObjenesisStd; +import org.springframework.objenesis.SpringObjenesis; /** - * Objenesis based extension of {@link CglibAopProxy} to create proxy instances without - * invoking the constructor of the class. + * Objenesis-based extension of {@link CglibAopProxy} to create proxy instances + * without invoking the constructor of the class. * * @author Oliver Gierke + * @author Juergen Hoeller * @since 4.0 */ @SuppressWarnings("serial") @@ -37,16 +40,17 @@ class ObjenesisCglibAopProxy extends CglibAopProxy { private static final Log logger = LogFactory.getLog(ObjenesisCglibAopProxy.class); - private final ObjenesisStd objenesis; + private static final Objenesis cachedObjenesis = new SpringObjenesis(); + + private static final Objenesis nonCachedObjenesis = new ObjenesisStd(false); /** - * Creates a new {@link ObjenesisCglibAopProxy} using the given {@link AdvisedSupport}. - * @param config must not be {@literal null}. + * Create a new ObjenesisCglibAopProxy for the given AOP configuration. + * @param config the AOP configuration as AdvisedSupport object */ public ObjenesisCglibAopProxy(AdvisedSupport config) { super(config); - this.objenesis = new ObjenesisStd(true); } @@ -54,15 +58,14 @@ class ObjenesisCglibAopProxy extends CglibAopProxy { @SuppressWarnings("unchecked") protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) { try { - Factory factory = (Factory) this.objenesis.newInstance(enhancer.createClass()); + Objenesis objenesis = (enhancer.getUseCache() ? cachedObjenesis : nonCachedObjenesis); + Factory factory = (Factory) objenesis.newInstance(enhancer.createClass()); factory.setCallbacks(callbacks); return factory; } catch (ObjenesisException ex) { // Fallback to regular proxy construction on unsupported JVMs - if (logger.isDebugEnabled()) { - logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", ex); - } + logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", ex); return super.createProxyClassAndInstance(enhancer, callbacks); } } diff --git a/spring-core/src/main/java/org/springframework/objenesis/SpringObjenesis.java b/spring-core/src/main/java/org/springframework/objenesis/SpringObjenesis.java new file mode 100644 index 0000000000..8a3893d98a --- /dev/null +++ b/spring-core/src/main/java/org/springframework/objenesis/SpringObjenesis.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2015 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.objenesis; + +import org.springframework.objenesis.instantiator.ObjectInstantiator; +import org.springframework.objenesis.strategy.InstantiatorStrategy; +import org.springframework.objenesis.strategy.StdInstantiatorStrategy; +import org.springframework.util.ConcurrentReferenceHashMap; + +/** + * Spring-specific variant of {@link ObjenesisStd} / {@link ObjenesisBase}, + * providing a cache based on {@code Class} keys instead of class names. + * + * @author Juergen Hoeller + * @since 4.2 + */ +public class SpringObjenesis implements Objenesis { + + private final InstantiatorStrategy strategy = new StdInstantiatorStrategy(); + + private final ConcurrentReferenceHashMap, ObjectInstantiator> cache = + new ConcurrentReferenceHashMap, ObjectInstantiator>(); + + + public T newInstance(Class clazz) { + return getInstantiatorOf(clazz).newInstance(); + } + + @SuppressWarnings("unchecked") + public ObjectInstantiator getInstantiatorOf(Class clazz) { + ObjectInstantiator instantiator = this.cache.get(clazz); + if (instantiator == null) { + ObjectInstantiator newInstantiator = this.strategy.newInstantiatorOf(clazz); + instantiator = this.cache.putIfAbsent(clazz, newInstantiator); + if (instantiator == null) { + instantiator = newInstantiator; + } + } + return (ObjectInstantiator) instantiator; + } + +} diff --git a/spring-core/src/main/java/org/springframework/objenesis/package-info.java b/spring-core/src/main/java/org/springframework/objenesis/package-info.java new file mode 100644 index 0000000000..2c5158a75f --- /dev/null +++ b/spring-core/src/main/java/org/springframework/objenesis/package-info.java @@ -0,0 +1,15 @@ +/** + * Spring's repackaging of + * Objenesis 2.1 + * (for internal use only). + * + *

This repackaging technique avoids any potential conflicts with + * dependencies on different Objenesis versions at the application + * level or from third-party libraries and frameworks. + * + *

As this repackaging happens at the class file level, sources + * and javadocs are not available here. See the original + * Objenesis docs + * for details when working with these classes. + */ +package org.springframework.objenesis; 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 abdc8049c7..fdd7fa3d46 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-2014 the original author or authors. + * Copyright 2002-2015 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. @@ -40,7 +40,8 @@ import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.objenesis.ObjenesisStd; +import org.springframework.objenesis.Objenesis; +import org.springframework.objenesis.SpringObjenesis; import org.springframework.util.AntPathMatcher; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -79,7 +80,7 @@ public class MvcUriComponentsBuilder extends UriComponentsBuilder { private static final Log logger = LogFactory.getLog(MvcUriComponentsBuilder.class); - private static final ObjenesisStd objenesis = new ObjenesisStd(true); + private static final Objenesis objenesis = new SpringObjenesis(); private static final PathMatcher pathMatcher = new AntPathMatcher();