From 4926603c210dfa069435a462f2a0cc06dbd12fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Thu, 15 Jun 2023 14:30:09 +0800 Subject: [PATCH] =?UTF-8?q?fix=20=E4=BF=AE=E5=A4=8D=20=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=20seata=20=E5=AE=98=E6=96=B9=E6=8F=90=E4=BA=A4=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=20=E4=B8=B4=E6=97=B6=E4=BF=AE=E5=A4=8D=20seata=20?= =?UTF-8?q?=E5=85=B3=E4=BA=8Ejdk17=E4=BB=A3=E7=90=86=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../seata/spring/util/SpringProxyUtils.java | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 ruoyi-common/ruoyi-common-seata/src/main/java/io/seata/spring/util/SpringProxyUtils.java diff --git a/ruoyi-common/ruoyi-common-seata/src/main/java/io/seata/spring/util/SpringProxyUtils.java b/ruoyi-common/ruoyi-common-seata/src/main/java/io/seata/spring/util/SpringProxyUtils.java new file mode 100644 index 00000000..483d7c83 --- /dev/null +++ b/ruoyi-common/ruoyi-common-seata/src/main/java/io/seata/spring/util/SpringProxyUtils.java @@ -0,0 +1,188 @@ +/* + * Copyright 1999-2019 Seata.io Group. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.seata.spring.util; + +import io.seata.common.util.CollectionUtils; +import io.seata.rm.tcc.remoting.parser.DubboUtil; +import org.springframework.aop.TargetSource; +import org.springframework.aop.framework.Advised; +import org.springframework.aop.framework.AdvisedSupport; +import org.springframework.aop.support.AopUtils; + +import java.lang.reflect.Field; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Proxy tools base on spring + * + * 临时修复 seata 适配 jdk17 反射bug + * + * @author zhangsen + */ +public class SpringProxyUtils { + private SpringProxyUtils() { + } + + /** + * Find target class class. + * + * @param proxy the proxy + * @return the class + * @throws Exception the exception + */ + public static Class findTargetClass(Object proxy) throws Exception { + if (proxy == null) { + return null; + } + if (AopUtils.isAopProxy(proxy) && proxy instanceof Advised) { + // #issue 3709 + final TargetSource targetSource = ((Advised) proxy).getTargetSource(); + if (!targetSource.isStatic()) { + return targetSource.getTargetClass(); + } + return findTargetClass(targetSource.getTarget()); + } + return proxy.getClass(); + } + + public static Class[] findInterfaces(Object proxy) throws Exception { + if (AopUtils.isJdkDynamicProxy(proxy)) { + AdvisedSupport advised = getAdvisedSupport(proxy); + return getInterfacesByAdvised(advised); + } else { + return new Class[]{}; + } + } + + private static Class[] getInterfacesByAdvised(AdvisedSupport advised) { + Class[] interfaces = advised.getProxiedInterfaces(); + if (interfaces.length > 0) { + return interfaces; + } else { + throw new IllegalStateException("Find the jdk dynamic proxy class that does not implement the interface"); + } + } + + /** + * Gets advised support. + * + * @param proxy the proxy + * @return the advised support + * @throws Exception the exception + */ + public static AdvisedSupport getAdvisedSupport(Object proxy) throws Exception { + Object dynamicAdvisedInterceptor; + if (AopUtils.isJdkDynamicProxy(proxy)) { + dynamicAdvisedInterceptor = Proxy.getInvocationHandler(proxy); + } else { + Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); + h.setAccessible(true); + dynamicAdvisedInterceptor = h.get(proxy); + } + Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); + advised.setAccessible(true); + return (AdvisedSupport)advised.get(dynamicAdvisedInterceptor); + } + + /** + * Is proxy boolean. + * + * @param bean the bean + * @return the boolean + */ + public static boolean isProxy(Object bean) { + if (bean == null) { + return false; + } + //check dubbo proxy ? + return DubboUtil.isDubboProxyName(bean.getClass().getName()) || (Proxy.class.isAssignableFrom(bean.getClass()) + || AopUtils.isAopProxy(bean)); + } + + /** + * Get the target class , get the interface of its agent if it is a Proxy + * + * @param proxy the proxy + * @return target interface + * @throws Exception the exception + */ + public static Class getTargetInterface(Object proxy) throws Exception { + if (proxy == null) { + throw new java.lang.IllegalArgumentException("proxy can not be null"); + } + + //jdk proxy + if (Proxy.class.isAssignableFrom(proxy.getClass())) { + Proxy p = (Proxy)proxy; + return p.getClass().getInterfaces()[0]; + } + + return getTargetClass(proxy); + } + + /** + * Get the class type of the proxy target object, if hadn't a target object, return the interface of the proxy + * + * @param proxy the proxy + * @return target interface + * @throws Exception the exception + */ + protected static Class getTargetClass(Object proxy) throws Exception { + if (proxy == null) { + throw new java.lang.IllegalArgumentException("proxy can not be null"); + } + //not proxy + if (!AopUtils.isAopProxy(proxy)) { + return proxy.getClass(); + } + AdvisedSupport advisedSupport = getAdvisedSupport(proxy); + Object target = advisedSupport.getTargetSource().getTarget(); + /* + * the Proxy of sofa:reference has no target + */ + if (target == null) { + if (CollectionUtils.isNotEmpty(advisedSupport.getProxiedInterfaces())) { + return advisedSupport.getProxiedInterfaces()[0]; + } else { + return proxy.getClass(); + } + } else { + return getTargetClass(target); + } + } + + /** + * get the all interfaces of bean, if the bean is null, then return empty array + * @param bean the bean + * @return target interface + */ + public static Class[] getAllInterfaces(Object bean) { + Set> interfaces = new HashSet<>(); + if (bean != null) { + Class clazz = bean.getClass(); + while (!Object.class.getName().equalsIgnoreCase(clazz.getName())) { + Class[] clazzInterfaces = clazz.getInterfaces(); + interfaces.addAll(Arrays.asList(clazzInterfaces)); + clazz = clazz.getSuperclass(); + } + } + return interfaces.toArray(new Class[0]); + } + +}