This commit is contained in:
Looly 2024-07-14 19:32:23 +08:00
parent 213b290f53
commit 73c715b662
3 changed files with 140 additions and 83 deletions

View File

@ -15,8 +15,7 @@ package org.dromara.hutool.core.bean;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.map.reference.WeakConcurrentMap;
import org.dromara.hutool.core.reflect.FieldUtil;
import java.lang.reflect.Proxy;
import org.dromara.hutool.core.reflect.JdkProxyUtil;
/**
* Bean描述信息工厂类<br>
@ -52,7 +51,7 @@ public class BeanDescFactory {
public static BeanDesc getBeanDescWithoutCache(final Class<?> clazz) {
if (RecordUtil.isRecord(clazz)) {
return new RecordBeanDesc(clazz);
} else if (isProxyClass(clazz) || ArrayUtil.isEmpty(FieldUtil.getFields(clazz))) {
} else if (JdkProxyUtil.isProxyClass(clazz) || ArrayUtil.isEmpty(FieldUtil.getFields(clazz))) {
// 代理类和空字段的Bean不支持属性获取直接使用方法方式
return new SimpleBeanDesc(clazz);
} else {
@ -68,11 +67,4 @@ public class BeanDescFactory {
public static void clearCache() {
bdCache.clear();
}
private static boolean isProxyClass(final Class<?> clazz) {
// JDK代理类
return Proxy.isProxyClass(clazz) ||
// cglib代理类
clazz.getName().contains("$$");
}
}

View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* https://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.reflect;
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
import org.dromara.hutool.core.lang.Assert;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* JDK的{@link Proxy}相关工具类封装
*
* @author Looly
* @since 6.0.0
*/
public class JdkProxyUtil {
private static final String CGLIB_CLASS_SEPARATOR = "$$";
// region ----- newProxyInstance
/**
* 创建动态代理对象<br>
* 动态代理对象的创建原理是<br>
* 假设创建的代理对象名为 $Proxy0
* 1根据传入的interfaces动态生成一个类实现interfaces中的接口<br>
* 2通过传入的classloder将刚生成的类加载到jvm中即将$Proxy0类load<br>
* 3调用$Proxy0的$Proxy0(InvocationHandler)构造函数 创建$Proxy0的对象并且用interfaces参数遍历其所有接口的方法这些实现方法的实现本质上是通过反射调用被代理对象的方法<br>
* 4将$Proxy0的实例返回给客户端 <br>
* 5当调用代理类的相应方法时相当于调用 {@link InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])} 方法
*
* @param <T> 被代理对象类型
* @param classloader 被代理类对应的ClassLoader
* @param invocationHandler {@link InvocationHandler} 被代理类通过实现此接口提供动态代理功能
* @param interfaces 代理类中需要实现的被代理类的接口方法
* @return 代理类
*/
@SuppressWarnings("unchecked")
public static <T> T newProxyInstance(final ClassLoader classloader, final InvocationHandler invocationHandler, final Class<?>... interfaces) {
return (T) Proxy.newProxyInstance(classloader, interfaces, invocationHandler);
}
/**
* 创建动态代理对象
*
* @param <T> 被代理对象类型
* @param invocationHandler {@link InvocationHandler} 被代理类通过实现此接口提供动态代理功能
* @param interfaces 代理类中需要实现的被代理类的接口方法
* @return 代理类
*/
public static <T> T newProxyInstance(final InvocationHandler invocationHandler, final Class<?>... interfaces) {
return newProxyInstance(ClassLoaderUtil.getClassLoader(), invocationHandler, interfaces);
}
// endregion
// region ----- isProxy
/**
* 是否为代理对象判断JDK代理或Cglib代理
*
* @param object 被检查的对象
* @return 是否为代理对象
*/
public static boolean isProxy(final Object object) {
Assert.notNull(object);
return isProxyClass(object.getClass());
}
/**
* 是否为JDK代理对象
*
* @param object 被检查的对象
* @return 是否为JDK代理对象
*/
public static boolean isJdkProxy(final Object object) {
Assert.notNull(object);
return isJdkProxyClass(object.getClass());
}
/**
* 是否Cglib代理对象
*
* @param object 被检查的对象
* @return 是否Cglib代理对象
*/
public static boolean isCglibProxy(final Object object) {
Assert.notNull(object);
return isCglibProxyClass(object.getClass());
}
// endregion
// region ----- isProxyClass
/**
* 是否为代理类判断JDK代理或Cglib代理
*
* @param clazz 被检查的类
* @return 是否为代理类
*/
public static boolean isProxyClass(final Class<?> clazz) {
return isJdkProxyClass(clazz) || isCglibProxyClass(clazz);
}
/**
* 是否为JDK代理类
*
* @param clazz 被检查的类
* @return 是否为JDK代理类
*/
public static boolean isJdkProxyClass(final Class<?> clazz) {
return Proxy.isProxyClass(Assert.notNull(clazz));
}
/**
* 是否Cglib代理对象
*
* @param clazz 被检查的对象
* @return 是否Cglib代理对象
*/
public static boolean isCglibProxyClass(final Class<?> clazz) {
return Assert.notNull(clazz).getName().contains(CGLIB_CLASS_SEPARATOR);
}
// endregion
}

View File

@ -12,21 +12,16 @@
package org.dromara.hutool.extra.aop;
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
import org.dromara.hutool.core.reflect.JdkProxyUtil;
import org.dromara.hutool.extra.aop.engine.ProxyEngine;
import org.dromara.hutool.extra.aop.engine.ProxyEngineFactory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* 代理工具类
*
* @author Looly
*/
public class ProxyUtil {
private static final String CGLIB_CLASS_SEPARATOR = "$$";
public class ProxyUtil extends JdkProxyUtil {
/**
* 获取动态代理引擎
@ -60,70 +55,4 @@ public class ProxyUtil {
public static <T> T proxy(final T target, final Aspect aspect) {
return getEngine().proxy(target, aspect);
}
// region ----- JDK Proxy utils
/**
* 创建动态代理对象<br>
* 动态代理对象的创建原理是<br>
* 假设创建的代理对象名为 $Proxy0
* 1根据传入的interfaces动态生成一个类实现interfaces中的接口<br>
* 2通过传入的classloder将刚生成的类加载到jvm中即将$Proxy0类load<br>
* 3调用$Proxy0的$Proxy0(InvocationHandler)构造函数 创建$Proxy0的对象并且用interfaces参数遍历其所有接口的方法这些实现方法的实现本质上是通过反射调用被代理对象的方法<br>
* 4将$Proxy0的实例返回给客户端 <br>
* 5当调用代理类的相应方法时相当于调用 {@link InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])} 方法
*
* @param <T> 被代理对象类型
* @param classloader 被代理类对应的ClassLoader
* @param invocationHandler {@link InvocationHandler} 被代理类通过实现此接口提供动态代理功能
* @param interfaces 代理类中需要实现的被代理类的接口方法
* @return 代理类
*/
@SuppressWarnings("unchecked")
public static <T> T newProxyInstance(final ClassLoader classloader, final InvocationHandler invocationHandler, final Class<?>... interfaces) {
return (T) Proxy.newProxyInstance(classloader, interfaces, invocationHandler);
}
/**
* 创建动态代理对象
*
* @param <T> 被代理对象类型
* @param invocationHandler {@link InvocationHandler} 被代理类通过实现此接口提供动态代理功能
* @param interfaces 代理类中需要实现的被代理类的接口方法
* @return 代理类
*/
public static <T> T newProxyInstance(final InvocationHandler invocationHandler, final Class<?>... interfaces) {
return newProxyInstance(ClassLoaderUtil.getClassLoader(), invocationHandler, interfaces);
}
// endregion
/**
* 是否为代理对象判断JDK代理或Cglib代理
*
* @param object 被检查的对象
* @return 是否为代理对象
*/
public static boolean isProxy(final Object object) {
return isJdkProxy(object) || isCglibProxy(object);
}
/**
* 是否为JDK代理对象
*
* @param object 被检查的对象
* @return 是否为JDK代理对象
*/
public static boolean isJdkProxy(final Object object) {
return Proxy.isProxyClass(object.getClass());
}
/**
* 是否Cglib代理对象
*
* @param object 被检查的对象
* @return 是否Cglib代理对象
*/
public static boolean isCglibProxy(final Object object) {
return (object.getClass().getName().contains(CGLIB_CLASS_SEPARATOR));
}
}