Check for advisor-introduced interfaces specifically

See gh-31304
This commit is contained in:
Juergen Hoeller 2024-09-27 11:07:11 +02:00
parent d3dd01e227
commit 8680c43368
3 changed files with 53 additions and 27 deletions

View File

@ -34,6 +34,7 @@ import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.IntroductionInfo;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetSource;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
@ -222,15 +223,15 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
/**
* Add a new proxied interface.
* @param intf the additional interface to proxy
* @param ifc the additional interface to proxy
*/
public void addInterface(Class<?> intf) {
Assert.notNull(intf, "Interface must not be null");
if (!intf.isInterface()) {
throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
public void addInterface(Class<?> ifc) {
Assert.notNull(ifc, "Interface must not be null");
if (!ifc.isInterface()) {
throw new IllegalArgumentException("[" + ifc.getName() + "] is not an interface");
}
if (!this.interfaces.contains(intf)) {
this.interfaces.add(intf);
if (!this.interfaces.contains(ifc)) {
this.interfaces.add(ifc);
adviceChanged();
}
}
@ -238,12 +239,12 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
/**
* Remove a proxied interface.
* <p>Does nothing if the given interface isn't proxied.
* @param intf the interface to remove from the proxy
* @param ifc the interface to remove from the proxy
* @return {@code true} if the interface was removed; {@code false}
* if the interface was not found and hence could not be removed
*/
public boolean removeInterface(Class<?> intf) {
return this.interfaces.remove(intf);
public boolean removeInterface(Class<?> ifc) {
return this.interfaces.remove(ifc);
}
@Override
@ -252,15 +253,37 @@ public class AdvisedSupport extends ProxyConfig implements Advised {
}
@Override
public boolean isInterfaceProxied(Class<?> intf) {
public boolean isInterfaceProxied(Class<?> ifc) {
for (Class<?> proxyIntf : this.interfaces) {
if (intf.isAssignableFrom(proxyIntf)) {
if (ifc.isAssignableFrom(proxyIntf)) {
return true;
}
}
return false;
}
boolean hasUserSuppliedInterfaces() {
for (Class<?> ifc : this.interfaces) {
if (!SpringProxy.class.isAssignableFrom(ifc) && !isAdvisorIntroducedInterface(ifc)) {
return true;
}
}
return false;
}
private boolean isAdvisorIntroducedInterface(Class<?> ifc) {
for (Advisor advisor : this.advisors) {
if (advisor instanceof IntroductionAdvisor introductionAdvisor) {
for (Class<?> introducedInterface : introductionAdvisor.getInterfaces()) {
if (introducedInterface == ifc) {
return true;
}
}
}
}
return false;
}
@Override
public final Advisor[] getAdvisors() {

View File

@ -19,7 +19,6 @@ package org.springframework.aop.framework;
import java.io.Serializable;
import java.lang.reflect.Proxy;
import org.springframework.aop.SpringProxy;
import org.springframework.util.ClassUtils;
/**
@ -59,7 +58,7 @@ public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || !hasTargetInterfaces(config)) {
if (config.isOptimize() || config.isProxyTargetClass() || !config.hasUserSuppliedInterfaces()) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
@ -75,14 +74,4 @@ public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
}
}
private boolean hasTargetInterfaces(AdvisedSupport config) {
Class<?> targetClass = config.getTargetClass();
for (Class<?> ifc : config.getProxiedInterfaces()) {
if (targetClass != null ? ifc.isAssignableFrom(targetClass) : !SpringProxy.class.isAssignableFrom(ifc)) {
return true;
}
}
return false;
}
}

View File

@ -199,7 +199,7 @@ class ProxyFactoryTests {
Class<?>[] oldProxiedInterfaces = pf.getProxiedInterfaces();
long t = 555555L;
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(t);
pf.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class));
pf.addAdvisor(new DefaultIntroductionAdvisor(ti, TimeStamped.class));
Class<?>[] newProxiedInterfaces = pf.getProxiedInterfaces();
assertThat(newProxiedInterfaces).as("Advisor proxies one more interface after introduction").hasSize(oldProxiedInterfaces.length + 1);
@ -328,11 +328,11 @@ class ProxyFactoryTests {
}
@Test
void proxyTargetClassWithIntroducedInterface() {
void proxyTargetClassInCaseOfIntroducedInterface() {
ProxyFactory pf = new ProxyFactory();
pf.setTargetClass(MyDate.class);
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(0L);
pf.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class));
pf.addAdvisor(new DefaultIntroductionAdvisor(ti, TimeStamped.class));
Object proxy = pf.getProxy();
assertThat(AopUtils.isCglibProxy(proxy)).as("Proxy is a CGLIB proxy").isTrue();
assertThat(proxy).isInstanceOf(MyDate.class);
@ -340,6 +340,20 @@ class ProxyFactoryTests {
assertThat(AopProxyUtils.ultimateTargetClass(proxy)).isEqualTo(MyDate.class);
}
@Test
void proxyInterfaceInCaseOfNonTargetInterface() {
ProxyFactory pf = new ProxyFactory();
pf.setTargetClass(MyDate.class);
pf.addInterface(TimeStamped.class);
pf.addAdvice((MethodInterceptor) invocation -> {
throw new UnsupportedOperationException();
});
Object proxy = pf.getProxy();
assertThat(AopUtils.isJdkDynamicProxy(proxy)).as("Proxy is a JDK proxy").isTrue();
assertThat(proxy).isInstanceOf(TimeStamped.class);
assertThat(AopProxyUtils.ultimateTargetClass(proxy)).isEqualTo(MyDate.class);
}
@Test
void interfaceProxiesCanBeOrderedThroughAnnotations() {
Object proxy1 = new ProxyFactory(new A()).getProxy();