Make proxyTargetClass=true with introduction advice work for JDK proxy targets

Closes gh-27044
This commit is contained in:
Juergen Hoeller 2021-07-09 13:23:04 +02:00
parent 74f91339e2
commit c45c46dad7
2 changed files with 33 additions and 6 deletions

View File

@ -17,6 +17,7 @@
package org.springframework.aop.framework.autoproxy; package org.springframework.aop.framework.autoproxy;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -440,7 +441,17 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
ProxyFactory proxyFactory = new ProxyFactory(); ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this); proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) { if (proxyFactory.isProxyTargetClass()) {
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for (Class<?> ifc : beanClass.getInterfaces()) {
proxyFactory.addInterface(ifc);
}
}
}
else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) { if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true); proxyFactory.setProxyTargetClass(true);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.aop.TargetSource; import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.target.SingletonTargetSource; import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
@ -219,7 +220,7 @@ public class AutoProxyCreatorTests {
MutablePropertyValues pvs = new MutablePropertyValues(); MutablePropertyValues pvs = new MutablePropertyValues();
pvs.add("proxyFactoryBean", "false"); pvs.add("proxyFactoryBean", "false");
sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class, pvs); sac.registerSingleton("testAutoProxyCreator", IntroductionTestAutoProxyCreator.class, pvs);
sac.registerSingleton("noInterfaces", NoInterfaces.class); sac.registerSingleton("noInterfaces", NoInterfaces.class);
sac.registerSingleton("containerCallbackInterfacesOnly", ContainerCallbackInterfacesOnly.class); sac.registerSingleton("containerCallbackInterfacesOnly", ContainerCallbackInterfacesOnly.class);
@ -248,9 +249,9 @@ public class AutoProxyCreatorTests {
singletonNoInterceptor.getName(); singletonNoInterceptor.getName();
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(0); assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(0);
singletonToBeProxied.getAge(); singletonToBeProxied.getAge();
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(1);
prototypeToBeProxied.getSpouse();
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(2); assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(2);
prototypeToBeProxied.getSpouse();
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(4);
} }
@Test @Test
@ -404,7 +405,7 @@ public class AutoProxyCreatorTests {
else if (name.endsWith("ToBeProxied")) { else if (name.endsWith("ToBeProxied")) {
boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass); boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass);
if ((this.proxyFactoryBean && isFactoryBean) || (this.proxyObject && !isFactoryBean)) { if ((this.proxyFactoryBean && isFactoryBean) || (this.proxyObject && !isFactoryBean)) {
return new Object[] {this.testInterceptor}; return getAdvicesAndAdvisors();
} }
else { else {
return DO_NOT_PROXY; return DO_NOT_PROXY;
@ -414,6 +415,10 @@ public class AutoProxyCreatorTests {
return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS; return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
} }
} }
protected Object[] getAdvicesAndAdvisors() {
return new Object[] {this.testInterceptor};
}
} }
@ -426,6 +431,17 @@ public class AutoProxyCreatorTests {
} }
@SuppressWarnings("serial")
public static class IntroductionTestAutoProxyCreator extends TestAutoProxyCreator {
protected Object[] getAdvicesAndAdvisors() {
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(this.testInterceptor);
advisor.addInterface(Serializable.class);
return new Object[] {this.testInterceptor, advisor};
}
}
/** /**
* Interceptor that counts the number of non-finalize method calls. * Interceptor that counts the number of non-finalize method calls.
*/ */