User1291
User1291

Reputation: 8199

How do you figure out whether a CLASS is a spring proxy?

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).

screenshot of misbehaving code

Upvotes: 2

Views: 2910

Answers (2)

Kirill Gamazkov
Kirill Gamazkov

Reputation: 3397

In now want to check whether a bean class is proxied without instantiating the bean (i.e. just with its class) in a BeanFactoryPostProcessor.

This task seems impossible to me since there are 100500 ways to proxy bean at runtime (bean post processor, advice, etc). Technically you can use random to decide whether to proxy some bean. You can have two instances of a given class (e.g. with different qualifiers), one proxied, other not.

Upvotes: 0

kriegaex
kriegaex

Reputation: 67417

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.

Upvotes: 1

Related Questions