Skip to content

Commit

Permalink
Document limitations of CGLIB proxy class generation in JPMS module s…
Browse files Browse the repository at this point in the history
…etups

Includes extended exception messages with common hints and explanations.

Closes gh-32671
  • Loading branch information
jhoeller committed May 8, 2024
1 parent 6250b64 commit 0eb937a
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 6 deletions.
4 changes: 4 additions & 0 deletions framework-docs/modules/ROOT/pages/core/aop/proxying.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<aop:config>` element to true, as follows:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
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;
Expand All @@ -37,6 +38,7 @@
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;
Expand Down Expand Up @@ -106,12 +108,19 @@ public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader)
}
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;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,15 @@ public String getMessage() {

// 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.
Expand Down

0 comments on commit 0eb937a

Please sign in to comment.