Document limitations of CGLIB proxy class generation in JPMS module setups
Includes extended exception messages with common hints and explanations. Closes gh-32671
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user