【问题标题】:How do you figure out whether a CLASS is a spring proxy?您如何确定 CLASS 是否是 spring 代理?
【发布时间】:2020-09-24 12:15:20
【问题描述】:

简而言之

AopUtils,我们有

    /**
     * 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)));
    }

现在想检查一个 bean 类是否被代理而不在 BeanFactoryPostProcessor 中实例化 bean(即仅使用它的类)。

我以为我可以“翻译”上述方法:

    private fun <T> isAopProxyClass(candidate: Class<T>): Boolean {
        return SpringProxy::class.java.isAssignableFrom(candidate)
            && (
            Proxy.isProxyClass(candidate)
                || candidate.name.contains(CGLIB_CLASS_SEPARATOR)
            )
    }

但这不会检测代理,因为 SpringProxy::class.java.isAssignableFrom(candidate)false,即使对于明显代理的类。

我该如何进行这项工作?

全图

我在 BeanFactoryPostProcessor 中,我需要未代理的 bean 类来通过反射访问某些带注释的方法。

访问发生在 lambda 函数中,该函数将首先使用 ApplicationContext 检索类的 bean。不能在 BeanFactoryPostProcessor 中强制实例化 bean(实际上应该抛出异常,因为某些 bean 是会话范围的)。

【问题讨论】:

  • 为什么 Class object 会成为 Spring 代理?您的意思是 可以 类实例由 Spring 代理吗?您必须检查它们是否带有 @Component 注释,例如我猜。或者绑定到 Spring 内部以检测它将扫描哪些类。
  • 你的意思是这样? stackoverflow.com/questions/8121551/…
  • @Kayaman 让我再试一次......我想弄清楚 Spring 是否会代理组件而不创建 bean 来检查它,只使用类对象。您链接到的问题需要一个实例化的 bean。
  • Class 永远不会是 instanceof 或可分配给任何“有用”的东西。只有从中出来的 bean(或带有例如 .newInstance() 的非 bean)才会响应这些。所以你基本上只能访问元数据。
  • @Kayaman 你确定吗?因为我对你的评论想得更多,这对我来说听起来不对。 Class::isAssignableFrom 检查,引用“如果此 Class 对象表示的类或接口与指定的 Class 参数表示的类或接口相同,或者是其超类或超接口”。所以如果 AopUtils 检查object instanceof SpringProxy,那么它的类应该满足这个检查,不是吗?

标签: java spring kotlin reflection spring-aop


【解决方案1】:

有趣的问题。 ?

屏幕截图中突出显示的三个类是 CGLIB 代理,但不是 AOP 代理。看他们的类名:都是Spring配置类。但这并不能使它们成为普通的 Spring 代理,尤其是 AOP 代理。关于@Component@Configuration的区别,还有关于代理和自调用行为,请阅读my answer here

因此,Spring @Configuration 类也不像普通 Spring 代理那样实现 SpringProxy

所以基本上你的解决方案工作得很好,不用担心,据我所知。

P.S.:我是 Java 人,不是 Kotlin 人。所以我从 Java 的屏幕截图中重新实现了你的代码,这样我就可以调试它并重现你的情况。但即使在 Kotlin 中,我也必须重新输入所有内容。请下次将代码发布为可复制的文本,而不仅仅是图像。


更新:如果你检查类似的内容

beanClasses.stream()
  .filter(aClass -> 
    aClass.getName().contains(CGLIB_CLASS_SEPARATOR) && 
      aClass.getSuperclass().getAnnotation(Configuration.class) == null
  )
  .collect(Collectors.toList())

你应该看到一个空集合,而

beanClasses.stream()
  .filter(aClass -> 
    aClass.getName().contains(CGLIB_CLASS_SEPARATOR) && 
      aClass.getSuperclass().getAnnotation(Configuration.class) != null
  )
  .collect(Collectors.toList())

应该产生与简单相同的类列表

beanClasses.stream()
  .filter(aClass -> aClass.getName().contains(CGLIB_CLASS_SEPARATOR))
  .collect(Collectors.toList())

beanClasses 中所有剩余的 CGLIB 代理实际上应该是配置,而不是普通的 Spring 代理。

【讨论】:

  • 请注意,我刚刚用一些解释性示例代码更新了答案,以证明我的陈述。
猜你喜欢
  • 2011-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
  • 2015-06-20
  • 2018-01-19
  • 2012-09-15
相关资源
最近更新 更多