CACHE = new ClassLoaderScopedClassCache<>();
public static ClassDescription getDescription(Class> type) {
return CACHE.computeIfAbsent(type, ClassDescription::new);
}
+ static void clearCache() {
+ CACHE.clear();
+ }
+
+ static void clearCache(ClassLoader loader) {
+ CACHE.clear(loader);
+ }
+
}
diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassLoaderScopedClassCache.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassLoaderScopedClassCache.java
new file mode 100644
index 000000000..d036839a4
--- /dev/null
+++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/ClassLoaderScopedClassCache.java
@@ -0,0 +1,45 @@
+package org.hswebframework.web.bean;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+
+/**
+ * 按 classloader 分段的 Class 维度强缓存。
+ *
+ * 普通稳定 classloader 直接走强缓存,动态 classloader 场景也保持强缓存命中,
+ * 通过 {@link #clear(ClassLoader)} 显式回收对应分段,避免弱/软引用在热路径上导致缓存重建。
+ *
+ * @param value type
+ * @author zhouhao
+ * @since 5.0.2
+ */
+final class ClassLoaderScopedClassCache {
+
+ private final Map, V> stableCache = new ConcurrentHashMap<>();
+ private final Map, V>> volatileCache = new ConcurrentHashMap<>();
+
+ V computeIfAbsent(Class> type, Function, V> mappingFunction) {
+ if (!FastBeanCopierSupport.isVolatileClassLoaderType(type)) {
+ return stableCache.computeIfAbsent(type, mappingFunction);
+ }
+ ClassLoader loader = FastBeanCopierSupport.getClassLoader(type);
+ return volatileCache
+ .computeIfAbsent(loader, ignore -> new ConcurrentHashMap<>())
+ .computeIfAbsent(type, mappingFunction);
+ }
+
+ void clear() {
+ stableCache.clear();
+ volatileCache.clear();
+ }
+
+ void clear(ClassLoader loader) {
+ if (loader == null) {
+ clear();
+ return;
+ }
+ stableCache.keySet().removeIf(type -> FastBeanCopierSupport.isClassLoaderMatch(type, loader));
+ volatileCache.remove(loader);
+ }
+}
diff --git a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
index fdb5fec9f..d542fe275 100644
--- a/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
+++ b/hsweb-core/src/main/java/org/hswebframework/web/bean/FastBeanCopier.java
@@ -1,781 +1,114 @@
package org.hswebframework.web.bean;
-import com.google.common.collect.Maps;
-import io.netty.util.internal.ConcurrentSet;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.beanutils.BeanUtilsBean;
-import org.apache.commons.beanutils.ConvertUtilsBean;
-import org.apache.commons.beanutils.PropertyUtilsBean;
-import org.hswebframework.ezorm.core.Extendable;
-import org.hswebframework.utils.time.DateFormatter;
-import org.hswebframework.web.dict.EnumDict;
-import org.hswebframework.web.proxy.Proxy;
-import org.hswebframework.web.utils.DynamicArrayList;
-import org.springframework.core.ResolvableType;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.NumberUtils;
-import org.springframework.util.ReflectionUtils;
-
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.Array;
-import java.lang.reflect.Field;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.function.BiFunction;
-import java.util.function.Function;
+import java.util.Set;
import java.util.function.Supplier;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
- * @author zhouhao
- * @since 3.0
+ * FastBeanCopier facade.
*/
-@Slf4j
public final class FastBeanCopier {
- private static final Map CACHE = new ConcurrentHashMap<>();
-
- private static final PropertyUtilsBean propertyUtils = BeanUtilsBean.getInstance().getPropertyUtils();
-
- private static final ConvertUtilsBean convertUtils = BeanUtilsBean.getInstance().getConvertUtils();
-
- private static final Map, Class>> wrapperClassMapping = new HashMap<>();
@SuppressWarnings("all")
- public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
+ public static final Class[] EMPTY_CLASS_ARRAY = FastBeanCopierSupport.EMPTY_CLASS_ARRAY;
- private static BeanFactory BEAN_FACTORY;
+ /**
+ * @deprecated 请改用 {@link FastBeanCopierSupport#DEFAULT_CONVERT}
+ */
+ @Deprecated
+ public static final DefaultConverter DEFAULT_CONVERT = new DefaultConverter();
- public static final DefaultConverter DEFAULT_CONVERT;
+ private FastBeanCopier() {
+ }
public static void setBeanFactory(BeanFactory beanFactory) {
- BEAN_FACTORY = beanFactory;
+ FastBeanCopierSupport.setBeanFactory(beanFactory);
DEFAULT_CONVERT.setBeanFactory(beanFactory);
}
public static BeanFactory getBeanFactory() {
- return BEAN_FACTORY;
+ return FastBeanCopierSupport.getBeanFactory();
+ }
+
+ public static void setBackend(FastBeanCopierBackend backend) {
+ FastBeanCopierSupport.setBackend(backend);
}
- static {
- wrapperClassMapping.put(byte.class, Byte.class);
- wrapperClassMapping.put(short.class, Short.class);
- wrapperClassMapping.put(int.class, Integer.class);
- wrapperClassMapping.put(float.class, Float.class);
- wrapperClassMapping.put(double.class, Double.class);
- wrapperClassMapping.put(char.class, Character.class);
- wrapperClassMapping.put(boolean.class, Boolean.class);
- wrapperClassMapping.put(long.class, Long.class);
- BEAN_FACTORY = new BeanFactory() {
- @Override
- @SneakyThrows
- @SuppressWarnings("all")
- public T newInstance(Class beanType) {
- return beanType == Map.class ? (T) new HashMap<>() : beanType.newInstance();
- }
- };
- DEFAULT_CONVERT = new DefaultConverter();
- DEFAULT_CONVERT.setBeanFactory(BEAN_FACTORY);
+ public static FastBeanCopierBackend getBackend() {
+ return FastBeanCopierSupport.getBackend();
}
@SuppressWarnings("all")
public static Set include(String... inculdeProperties) {
- return new HashSet(Arrays.asList(inculdeProperties)) {
- @Override
- public boolean contains(Object o) {
- return !super.contains(o);
- }
- };
+ return FastBeanCopierSupport.include(inculdeProperties);
}
public static Object getProperty(Object source, String key) {
- if (source instanceof Map) {
- return ((Map, ?>) source).get(key);
- }
- SingleValueMap