您如何确定 CLASS 是否是 spring 代理?
How do you figure out whether a CLASS is a spring proxy?
一言以蔽之
在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 class 是否在 BeanFactoryPostProcessor
.
中被代理而不实例化 bean(即只用它的 class)
我以为我可以“翻译”上面的方法:
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
,即使对于明显被代理的 classes。
如何进行这项工作?
全图
我在 BeanFactoryPostProcessor
中,我需要未代理的 bean classes 来通过反射访问某些带注释的方法。
访问发生在 lambda 函数中,该函数将首先使用 ApplicationContext
检索 class 的 bean。不能在此 BeanFactoryPostProcessor
中强制实例化 bean(事实上,如果这样做,应该抛出异常,因为某些 bean 是会话范围的)。
有趣的问题。
屏幕截图中突出显示的三个 class 是 CGLIB 代理,但不是 AOP 代理。看他们的class名字:都是Spring配置class。但这并不能使它们成为正常的 Spring 代理,尤其是 AOP 代理。关于 @Component
和 @Configuration
之间的区别,以及关于代理和 self-invocation 行为,请阅读 。
因此,Spring @Configuration
class 也不像普通 Spring 代理那样实现 SpringProxy
。
所以基本上你的解决方案工作得很好,不用担心,据我所知。
P.S.: 我是 Java 人,不是 Kotlin 人。所以我 re-implemented 你的代码来自 Java 的截图,所以我可以调试它并重现你的情况。但即使在 Kotlin 中,我也必须 re-type 一切。下次请将代码发布为可复制的文本,而不仅仅是图像。
更新:如果你检查类似
的内容
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())
应该产生与
相同的 classes 列表
beanClasses.stream()
.filter(aClass -> aClass.getName().contains(CGLIB_CLASS_SEPARATOR))
.collect(Collectors.toList())
即beanClasses
中所有剩余的 CGLIB 代理实际上应该是配置,而不是正常的 Spring 代理。
一言以蔽之
在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 class 是否在 BeanFactoryPostProcessor
.
我以为我可以“翻译”上面的方法:
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
,即使对于明显被代理的 classes。
如何进行这项工作?
全图
我在 BeanFactoryPostProcessor
中,我需要未代理的 bean classes 来通过反射访问某些带注释的方法。
访问发生在 lambda 函数中,该函数将首先使用 ApplicationContext
检索 class 的 bean。不能在此 BeanFactoryPostProcessor
中强制实例化 bean(事实上,如果这样做,应该抛出异常,因为某些 bean 是会话范围的)。
有趣的问题。
屏幕截图中突出显示的三个 class 是 CGLIB 代理,但不是 AOP 代理。看他们的class名字:都是Spring配置class。但这并不能使它们成为正常的 Spring 代理,尤其是 AOP 代理。关于 @Component
和 @Configuration
之间的区别,以及关于代理和 self-invocation 行为,请阅读
因此,Spring @Configuration
class 也不像普通 Spring 代理那样实现 SpringProxy
。
所以基本上你的解决方案工作得很好,不用担心,据我所知。
P.S.: 我是 Java 人,不是 Kotlin 人。所以我 re-implemented 你的代码来自 Java 的截图,所以我可以调试它并重现你的情况。但即使在 Kotlin 中,我也必须 re-type 一切。下次请将代码发布为可复制的文本,而不仅仅是图像。
更新:如果你检查类似
的内容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())
应该产生与
相同的 classes 列表beanClasses.stream()
.filter(aClass -> aClass.getName().contains(CGLIB_CLASS_SEPARATOR))
.collect(Collectors.toList())
即beanClasses
中所有剩余的 CGLIB 代理实际上应该是配置,而不是正常的 Spring 代理。