Simplify hint registration for Spring AOP proxies
Prior to this commit, when users wished to register proxy hints for a Spring AOP JDK dynamic proxy, they were required to explicitly specify SpringProxy, Advised, and DecoratingProxy along with user interfaces. This commit simplifies hint registration for Spring AOP proxies by introducing two completeJdkProxyInterfaces() methods in AopProxyUtils, one that accepts strings and one that accepts classes that represent the user-specified interfaces implemented the user component to be proxied. The SpringProxy, Advised, and DecoratingProxy interfaces are appended to the user-specified interfaces and returned as the complete set of interfaces that the proxy will implement. Closes gh-28745
This commit is contained in:
@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.aop.SpringProxy;
|
||||
@@ -28,6 +29,8 @@ import org.springframework.aop.TargetClassAware;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.target.SingletonTargetSource;
|
||||
import org.springframework.aot.hint.ProxyHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.core.DecoratingProxy;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -93,6 +96,79 @@ public abstract class AopProxyUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the set of interfaces that are typically required in a JDK dynamic
|
||||
* proxy generated by Spring AOP.
|
||||
* <p>Specifically, {@link SpringProxy}, {@link Advised}, and {@link DecoratingProxy}
|
||||
* will be appended to the set of user-specified interfaces.
|
||||
* <p>Any {@linkplain Class#isSealed() sealed} interface in the set of
|
||||
* user-specified interfaces will be omitted from the results, since only
|
||||
* non-sealed interfaces are eligible for JDK dynamic proxies.
|
||||
* <p>This method can be useful when registering {@linkplain ProxyHints proxy
|
||||
* hints} for Spring's AOT support, as demonstrated in the following example
|
||||
* which uses this method via a {@code static} import.
|
||||
* <pre class="code">
|
||||
* RuntimeHints hints = ...
|
||||
* hints.proxies().registerJdkProxy(completeJdkProxyInterfaces(MyInterface.class));
|
||||
* </pre>
|
||||
* @param userInterfaces the set of user-specified interfaces implemented by
|
||||
* the component to be proxied
|
||||
* @return the complete set of interfaces that the proxy should implement
|
||||
* @since 6.0
|
||||
* @see SpringProxy
|
||||
* @see Advised
|
||||
* @see DecoratingProxy
|
||||
* @see RuntimeHints#proxies()
|
||||
* @see ProxyHints#registerJdkProxy(Class...)
|
||||
* @see #completeJdkProxyInterfaces(String...)
|
||||
*/
|
||||
public static Class<?>[] completeJdkProxyInterfaces(Class<?>... userInterfaces) {
|
||||
List<Class<?>> completedInterfaces = new ArrayList<>(userInterfaces.length + 3);
|
||||
for (Class<?> ifc : userInterfaces) {
|
||||
Assert.isTrue(ifc.isInterface(), () -> ifc.getName() + " must be an interface");
|
||||
if (!ifc.isSealed()) {
|
||||
completedInterfaces.add(ifc);
|
||||
}
|
||||
}
|
||||
completedInterfaces.add(SpringProxy.class);
|
||||
completedInterfaces.add(Advised.class);
|
||||
completedInterfaces.add(DecoratingProxy.class);
|
||||
return completedInterfaces.toArray(Class<?>[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the set of interfaces that are typically required in a JDK dynamic
|
||||
* proxy generated by Spring AOP.
|
||||
* <p>Specifically, {@link SpringProxy}, {@link Advised}, and {@link DecoratingProxy}
|
||||
* will be appended to the set of user-specified interfaces.
|
||||
* <p>This method can be useful when registering {@linkplain ProxyHints proxy
|
||||
* hints} for Spring's AOT support, as demonstrated in the following example
|
||||
* which uses this method via a {@code static} import.
|
||||
* <pre class="code">
|
||||
* RuntimeHints hints = ...
|
||||
* hints.proxies().registerJdkProxy(completeJdkProxyInterfaces("com.example.MyInterface"));
|
||||
* </pre>
|
||||
* @param userInterfaces the set of fully qualified names of user-specified
|
||||
* interfaces implemented by the component to be proxied
|
||||
* @return the complete set of fully qualified names of interfaces that the
|
||||
* proxy should implement
|
||||
* @since 6.0
|
||||
* @see SpringProxy
|
||||
* @see Advised
|
||||
* @see DecoratingProxy
|
||||
* @see RuntimeHints#proxies()
|
||||
* @see ProxyHints#registerJdkProxy(Class...)
|
||||
* @see #completeJdkProxyInterfaces(Class...)
|
||||
*/
|
||||
public static String[] completeJdkProxyInterfaces(String... userInterfaces) {
|
||||
List<String> completedInterfaces = new ArrayList<>(userInterfaces.length + 3);
|
||||
Collections.addAll(completedInterfaces, userInterfaces);
|
||||
completedInterfaces.add(SpringProxy.class.getName());
|
||||
completedInterfaces.add(Advised.class.getName());
|
||||
completedInterfaces.add(DecoratingProxy.class.getName());
|
||||
return completedInterfaces.toArray(String[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the complete set of interfaces to proxy for the given AOP configuration.
|
||||
* <p>This will always add the {@link Advised} interface unless the AdvisedSupport's
|
||||
|
||||
Reference in New Issue
Block a user