Issue
In a nutshell
In the AopUtils
, we have
/**
* Check whether the given object is a JDK dynamic proxy or a CGLIB proxy.
* <p>This method additionally checks if the given object is an instance
* of {@link SpringProxy}.
* @param object the object to check
* @see #isJdkDynamicProxy
* @see #isCglibProxy
*/
public static boolean isAopProxy(@Nullable Object object) {
return (object instanceof SpringProxy && (Proxy.isProxyClass(object.getClass()) ||
object.getClass().getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)));
}
In now want to check whether a bean class is proxied without instantiating the bean (i.e. just with its class) in a BeanFactoryPostProcessor
.
I thought I could just "translate" above method:
private fun <T> isAopProxyClass(candidate: Class<T>): Boolean {
return SpringProxy::class.java.isAssignableFrom(candidate)
&& (
Proxy.isProxyClass(candidate)
|| candidate.name.contains(CGLIB_CLASS_SEPARATOR)
)
}
But this does not detect proxies because SpringProxy::class.java.isAssignableFrom(candidate)
is false
even for obviously proxied classes.
How do I make this work?
Full picture
I'm in a BeanFactoryPostProcessor
and I need the un-proxied bean classes to access certain annotated methods by reflection.
Access happens in a lambda function that will first use the ApplicationContext
to retrieve the bean for the class. The bean must not be forcibly instantiated in this BeanFactoryPostProcessor
(and in fact should throw an exception if it does because some beans are session-scoped).
Solution
Interesting question. 😀
The three classes highlighted in your screenshot are CGLIB proxies but not AOP proxies. Look at their class names: They are all Spring configuration classes. But that does not make them normal Spring proxies, especially not AOP proxies. For the difference between @Component
and @Configuration
, also with regard to proxying and self-invocation behaviour, please read my answer here.
Consequently, a Spring @Configuration
class also does not implement SpringProxy
like normal Spring proxies.
So basically your solution works just fine, no need to worry, as far as I can see.
P.S.: I am a Java guy, not a Kotlin person. So I re-implemented your code from the screenshot in Java, so I could debug into it and reproduce your situation. But even in Kotlin I would have had to re-type everything. Please next time publish the code as copyable text, not just as an image.
Update: If you check something like the content of
beanClasses.stream()
.filter(aClass ->
aClass.getName().contains(CGLIB_CLASS_SEPARATOR) &&
aClass.getSuperclass().getAnnotation(Configuration.class) == null
)
.collect(Collectors.toList())
you should see an empty collection, whereas
beanClasses.stream()
.filter(aClass ->
aClass.getName().contains(CGLIB_CLASS_SEPARATOR) &&
aClass.getSuperclass().getAnnotation(Configuration.class) != null
)
.collect(Collectors.toList())
should yield the same list of classes as simply
beanClasses.stream()
.filter(aClass -> aClass.getName().contains(CGLIB_CLASS_SEPARATOR))
.collect(Collectors.toList())
I.e. all remaining CGLIB proxies in beanClasses
should in fact be configurations, not normal Spring proxies.
Answered By - kriegaex
Answer Checked By - Mary Flores (JavaFixing Volunteer)