diff --git a/framework-docs/modules/ROOT/pages/core/aop/proxying.adoc b/framework-docs/modules/ROOT/pages/core/aop/proxying.adoc index 0187cf3a59..44a76320f6 100644 --- a/framework-docs/modules/ROOT/pages/core/aop/proxying.adoc +++ b/framework-docs/modules/ROOT/pages/core/aop/proxying.adoc @@ -19,6 +19,10 @@ you can do so. However, you should consider the following issues: since the CGLIB proxy instance is created through Objenesis. Only if your JVM does not allow for constructor bypassing, you might see double invocations and corresponding debug log entries from Spring's AOP support. +* Your CGLIB proxy usage may face limitations with the JDK 9+ platform module system. + As a typical case, you cannot create a CGLIB proxy for a class from the `java.lang` + package when deploying on the module path. Such cases require a JVM bootstrap flag + `--add-opens=java.base/java.lang=ALL-UNNAMED` which is not available for modules. To force the use of CGLIB proxies, set the value of the `proxy-target-class` attribute of the `` element to true, as follows: 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 2521a0f2f5..15e5d97cc0 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 @@ -28,6 +28,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.aop.scope.ScopedProxyFactoryBean; import org.springframework.asm.Opcodes; import org.springframework.asm.Type; +import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -37,6 +38,7 @@ import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.support.SimpleInstantiationStrategy; import org.springframework.cglib.core.ClassGenerator; import org.springframework.cglib.core.ClassLoaderAwareGeneratorStrategy; +import org.springframework.cglib.core.CodeGenerationException; import org.springframework.cglib.core.SpringNamingPolicy; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.CallbackFilter; @@ -106,12 +108,19 @@ class ConfigurationClassEnhancer { } return configClass; } - Class enhancedClass = createClass(newEnhancer(configClass, classLoader)); - if (logger.isTraceEnabled()) { - logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s", - configClass.getName(), enhancedClass.getName())); + try { + Class enhancedClass = createClass(newEnhancer(configClass, classLoader)); + if (logger.isTraceEnabled()) { + logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s", + configClass.getName(), enhancedClass.getName())); + } + return enhancedClass; + } + catch (CodeGenerationException ex) { + throw new BeanDefinitionStoreException("Could not enhance configuration class [" + configClass.getName() + + "]. Consider declaring @Configuration(proxyBeanMethods=false) without inter-bean references " + + "between @Bean methods on the configuration class, avoiding the need for CGLIB enhancement.", ex); } - return enhancedClass; } /** diff --git a/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java b/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java index 33c44706d6..102f333c07 100644 --- a/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java +++ b/spring-core/src/main/java/org/springframework/cglib/core/ReflectUtils.java @@ -544,7 +544,15 @@ public class ReflectUtils { // No defineClass variant available at all? if (c == null) { - throw new CodeGenerationException(t); + throw new CodeGenerationException(t) { + @Override + public String getMessage() { + return "No compatible defineClass mechanism detected: " + + "JVM should be started with --add-opens=java.base/java.lang=ALL-UNNAMED " + + "for ClassLoader.defineClass to be accessible. On the module path, " + + "you may not be able to define this CGLIB-generated class at all."; + } + }; } // Force static initializers to run.