Merge pull request #1959 from lzpeng723/v5-dev

由于 FileObjectResource 的流不能读取多次,ResourceClassLoader 增加缓存,同一个类只能加载一次
This commit is contained in:
Golden Looly 2021-11-19 00:05:18 +08:00 committed by GitHub
commit 9a756eb4b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -7,18 +7,24 @@ import cn.hutool.core.util.ObjectUtil;
import java.security.SecureClassLoader; import java.security.SecureClassLoader;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* 资源类加载器可以加载任意类型的资源类 * 资源类加载器可以加载任意类型的资源类
* *
* @param <T> {@link Resource}接口实现类 * @param <T> {@link Resource}接口实现类
* @author looly * @author looly,lzpeng
* @since 5.5.2 * @since 5.5.2
*/ */
public class ResourceClassLoader<T extends Resource> extends SecureClassLoader { public class ResourceClassLoader<T extends Resource> extends SecureClassLoader {
private final Map<String, T> resourceMap; private final Map<String, T> resourceMap;
/**
* 缓存已经加载的类
*/
private final Map<String, Class> cacheClassMap;
/** /**
* 构造 * 构造
* *
@ -28,6 +34,7 @@ public class ResourceClassLoader<T extends Resource> extends SecureClassLoader {
public ResourceClassLoader(ClassLoader parentClassLoader, Map<String, T> resourceMap) { public ResourceClassLoader(ClassLoader parentClassLoader, Map<String, T> resourceMap) {
super(ObjectUtil.defaultIfNull(parentClassLoader, ClassLoaderUtil.getClassLoader())); super(ObjectUtil.defaultIfNull(parentClassLoader, ClassLoaderUtil.getClassLoader()));
this.resourceMap = ObjectUtil.defaultIfNull(resourceMap, new HashMap<>()); this.resourceMap = ObjectUtil.defaultIfNull(resourceMap, new HashMap<>());
this.cacheClassMap = new ConcurrentHashMap<>();
} }
/** /**
@ -42,11 +49,21 @@ public class ResourceClassLoader<T extends Resource> extends SecureClassLoader {
@Override @Override
protected Class<?> findClass(String name) throws ClassNotFoundException { protected Class<?> findClass(String name) throws ClassNotFoundException {
final Resource resource = resourceMap.get(name); final Class<?> clazz = cacheClassMap.computeIfAbsent(name, className -> {
if (null != resource) { final Resource resource = resourceMap.get(name);
final byte[] bytes = resource.readBytes(); if (null != resource) {
return defineClass(name, bytes, 0, bytes.length); final byte[] bytes = resource.readBytes();
return defineClass(name, bytes, 0, bytes.length);
}
try {
return super.findClass(name);
} catch (ClassNotFoundException e) {
return null;
}
});
if (clazz == null) {
throw new ClassNotFoundException(name);
} }
return super.findClass(name); return clazz;
} }
} }