Ensure Spring AOP generates JDK dynamic proxies for lambdas
Prior to this commit, if AOP proxy generation was configured with proxyTargetClass=true (which is the default behavior in recent versions of Spring Boot), beans implemented as lambda expressions or method references could not be proxied with CGLIB on Java 16 or higher without specifying `--add-opens java.base/java.lang=ALL-UNNAMED`. This commit addresses this shortcoming by ensuring that beans implemented as lambda expressions or method references are always proxied using a JDK dynamic proxy even if proxyTargetClass=true. Closes gh-27971
This commit is contained in:
@@ -19,6 +19,7 @@ package org.springframework.aop.aspectj.autoproxy;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
@@ -27,6 +28,8 @@ import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import org.springframework.aop.MethodBeforeAdvice;
|
||||
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
|
||||
@@ -42,6 +45,11 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.testfixture.beans.ITestBean;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
@@ -292,6 +300,16 @@ public class AspectJAutoProxyCreatorTests {
|
||||
assertThat(tb.getAge()).isEqualTo(68);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "[{index}] {0}")
|
||||
@ValueSource(classes = {ProxyTargetClassFalseConfig.class, ProxyTargetClassTrueConfig.class})
|
||||
void lambdaIsAlwaysProxiedWithJdkProxy(Class<?> configClass) {
|
||||
try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(configClass)) {
|
||||
Supplier<?> supplier = context.getBean(Supplier.class);
|
||||
assertThat(AopUtils.isAopProxy(supplier)).as("AOP proxy").isTrue();
|
||||
assertThat(AopUtils.isJdkDynamicProxy(supplier)).as("JDK Dynamic proxy").isTrue();
|
||||
assertThat(supplier.get()).asString().isEqualTo("advised: lambda");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link ClassPathXmlApplicationContext} for the file ending in <var>fileSuffix</var>.
|
||||
@@ -566,3 +584,35 @@ class TestBeanAdvisor extends StaticMethodMatcherPointcutAdvisor {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class AbstractProxyTargetClassConfig {
|
||||
|
||||
@Bean
|
||||
Supplier<String> stringSupplier() {
|
||||
return () -> "lambda";
|
||||
}
|
||||
|
||||
@Bean
|
||||
SupplierAdvice supplierAdvice() {
|
||||
return new SupplierAdvice();
|
||||
}
|
||||
|
||||
@Aspect
|
||||
static class SupplierAdvice {
|
||||
|
||||
@Around("execution(public * org.springframework.aop.aspectj.autoproxy..*.*(..))")
|
||||
Object aroundSupplier(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
return "advised: " + joinPoint.proceed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = false)
|
||||
class ProxyTargetClassFalseConfig extends AbstractProxyTargetClassConfig {
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
class ProxyTargetClassTrueConfig extends AbstractProxyTargetClassConfig {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user