mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix code
This commit is contained in:
parent
a280ff0918
commit
9781d5eb9f
@ -71,6 +71,21 @@ public class SimpleCache<K, V> implements Iterable<Map.Entry<K, V>>, Serializabl
|
||||
this.rawMap = initMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含键
|
||||
*
|
||||
* @param key 键
|
||||
* @return 是否包含
|
||||
*/
|
||||
public boolean containsKey(final K key) {
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
return rawMap.containsKey(MutableObj.of(key));
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从缓存池中查找值
|
||||
*
|
||||
|
@ -299,7 +299,7 @@ public class ResourceUtil {
|
||||
*
|
||||
* @param properties {@link Properties}文件
|
||||
* @param resource 资源
|
||||
* @param charset 编码,对XML无效
|
||||
* @param charset 编码,对XML无效,默认UTF-8
|
||||
*/
|
||||
public static void loadTo(final Properties properties, final Resource resource, final Charset charset) {
|
||||
Assert.notNull(properties);
|
||||
@ -329,7 +329,7 @@ public class ResourceUtil {
|
||||
* @param properties {@link Properties}文件
|
||||
* @param resourceName 资源名,可以是相对classpath的路径,也可以是绝对路径
|
||||
* @param classLoader {@link ClassLoader},{@code null}表示使用默认的当前上下文ClassLoader
|
||||
* @param charset 编码,对XML无效
|
||||
* @param charset 编码,对XML无效,默认UTF-8
|
||||
*/
|
||||
public static void loadAllTo(final Properties properties, final String resourceName,
|
||||
final ClassLoader classLoader, final Charset charset) {
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
package org.dromara.hutool.core.reflect;
|
||||
|
||||
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
|
||||
import org.dromara.hutool.core.exceptions.UtilException;
|
||||
import org.dromara.hutool.core.lang.Assert;
|
||||
import org.dromara.hutool.core.map.WeakConcurrentMap;
|
||||
@ -103,7 +104,7 @@ public class ConstructorUtil {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T newInstance(final String clazz) throws UtilException {
|
||||
try {
|
||||
return (T) Class.forName(clazz).newInstance();
|
||||
return (T) ClassLoaderUtil.loadClass(clazz).newInstance();
|
||||
} catch (final Exception e) {
|
||||
throw new UtilException(e, "Instance class [{}] error!", clazz);
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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:
|
||||
* http://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.spi;
|
||||
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
|
||||
/**
|
||||
* 抽象服务加载器,提供包括路径前缀、服务类、类加载器、编码、安全相关持有
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public abstract class AbsServiceLoader<S> implements ServiceLoader<S> {
|
||||
|
||||
protected final String pathPrefix;
|
||||
protected final Class<S> serviceClass;
|
||||
protected final ClassLoader classLoader;
|
||||
protected final Charset charset;
|
||||
protected final AccessControlContext acc;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param pathPrefix 路径前缀
|
||||
* @param serviceClass 服务名称
|
||||
* @param classLoader 自定义类加载器, {@code null}表示使用默认当前的类加载器
|
||||
* @param charset 编码,默认UTF-8
|
||||
*/
|
||||
public AbsServiceLoader(final String pathPrefix, final Class<S> serviceClass,
|
||||
final ClassLoader classLoader, final Charset charset) {
|
||||
this.pathPrefix = StrUtil.addSuffixIfNot(pathPrefix, StrUtil.SLASH);
|
||||
this.serviceClass = serviceClass;
|
||||
this.classLoader = classLoader;
|
||||
this.charset = charset;
|
||||
this.acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
|
||||
}
|
||||
}
|
@ -12,37 +12,92 @@
|
||||
|
||||
package org.dromara.hutool.core.spi;
|
||||
|
||||
import org.dromara.hutool.core.cache.SimpleCache;
|
||||
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
|
||||
import org.dromara.hutool.core.io.resource.ResourceUtil;
|
||||
import org.dromara.hutool.core.reflect.ConstructorUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.AccessUtil;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Properties;
|
||||
|
||||
public class KVServiceLoader<S> implements ServiceLoader<S>{
|
||||
/**
|
||||
* 键值对服务加载器,使用{@link Properties}加载并存储服务
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class KVServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
|
||||
private final String pathPrefix;
|
||||
private final Class<S> serviceClass;
|
||||
private final ClassLoader classLoader;
|
||||
private final Charset charset;
|
||||
private static final String PREFIX_HUTOOL = "META-INF/hutool/";
|
||||
|
||||
// region ----- of
|
||||
|
||||
/**
|
||||
* 构建KVServiceLoader
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @param serviceClass 服务名称
|
||||
* @return KVServiceLoader
|
||||
*/
|
||||
public static <S> KVServiceLoader<S> of(final Class<S> serviceClass) {
|
||||
return of(serviceClass, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建KVServiceLoader
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @param serviceClass 服务名称
|
||||
* @param classLoader 自定义类加载器, {@code null}表示使用默认当前的类加载器
|
||||
* @return KVServiceLoader
|
||||
*/
|
||||
public static <S> KVServiceLoader<S> of(final Class<S> serviceClass, final ClassLoader classLoader) {
|
||||
return of(PREFIX_HUTOOL, serviceClass, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建KVServiceLoader
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @param pathPrefix 路径前缀
|
||||
* @param serviceClass 服务名称
|
||||
* @param classLoader 自定义类加载器, {@code null}表示使用默认当前的类加载器
|
||||
* @return KVServiceLoader
|
||||
*/
|
||||
public static <S> KVServiceLoader<S> of(final String pathPrefix, final Class<S> serviceClass,
|
||||
final ClassLoader classLoader) {
|
||||
return new KVServiceLoader<>(pathPrefix, serviceClass, classLoader, null);
|
||||
}
|
||||
// endregion
|
||||
|
||||
private Properties serviceProperties;
|
||||
private final SimpleCache<String, S> serviceCache;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param pathPrefix 路径前缀
|
||||
* @param serviceClass 服务名称
|
||||
* @param classLoader 自定义类加载器, {@code null}表示使用默认当前的类加载器
|
||||
* @param charset 编码,默认UTF-8
|
||||
*/
|
||||
public KVServiceLoader(final String pathPrefix, final Class<S> serviceClass,
|
||||
final ClassLoader classLoader, final Charset charset) {
|
||||
this.pathPrefix = pathPrefix;
|
||||
this.serviceClass = serviceClass;
|
||||
this.classLoader = classLoader;
|
||||
this.charset = charset;
|
||||
super(pathPrefix, serviceClass, classLoader, charset);
|
||||
|
||||
this.serviceCache = new SimpleCache<>(new HashMap<>());
|
||||
load();
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载或重新加载全部服务
|
||||
* @return this
|
||||
*/
|
||||
public KVServiceLoader<S> load(){
|
||||
@Override
|
||||
public void load() {
|
||||
final Properties properties = new Properties();
|
||||
ResourceUtil.loadAllTo(
|
||||
properties,
|
||||
@ -50,15 +105,56 @@ public class KVServiceLoader<S> implements ServiceLoader<S>{
|
||||
classLoader,
|
||||
charset);
|
||||
this.serviceProperties = properties;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Class<S> getServiceClass(final String serviceName){
|
||||
@Override
|
||||
public int size() {
|
||||
return this.serviceProperties.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定服务的实现类
|
||||
*
|
||||
* @param serviceName 服务名称
|
||||
* @return 服务名称对应的实现类
|
||||
*/
|
||||
public Class<S> getServiceClass(final String serviceName) {
|
||||
return AccessUtil.doPrivileged(() -> getServiceClassUnsafe(serviceName), this.acc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定名称对应的服务,使用缓存,多次调用只返回相同的服务对象
|
||||
*
|
||||
* @param serviceName 服务名称
|
||||
* @return 服务对象
|
||||
*/
|
||||
public S getService(final String serviceName) {
|
||||
return this.serviceCache.get(serviceName, () -> createService(serviceName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建服务,无缓存
|
||||
*
|
||||
* @param serviceName 服务名称
|
||||
* @return 服务对象
|
||||
*/
|
||||
private S createService(final String serviceName) {
|
||||
return AccessUtil.doPrivileged(() ->
|
||||
ConstructorUtil.newInstance(getServiceClassUnsafe(serviceName)), this.acc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定服务的实现类
|
||||
*
|
||||
* @param serviceName 服务名称
|
||||
* @return 服务名称对应的实现类
|
||||
*/
|
||||
private Class<S> getServiceClassUnsafe(final String serviceName) {
|
||||
final String serviceClassName = this.serviceProperties.getProperty(serviceName);
|
||||
if(StrUtil.isNotBlank(serviceClassName)){
|
||||
return ClassLoaderUtil.loadClass(serviceClassName);
|
||||
if (StrUtil.isBlank(serviceClassName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
return ClassLoaderUtil.loadClass(serviceClassName);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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:
|
||||
* http://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.spi;
|
||||
|
||||
import org.dromara.hutool.core.cache.SimpleCache;
|
||||
import org.dromara.hutool.core.io.IORuntimeException;
|
||||
import org.dromara.hutool.core.io.resource.MultiResource;
|
||||
import org.dromara.hutool.core.io.resource.Resource;
|
||||
import org.dromara.hutool.core.io.resource.ResourceUtil;
|
||||
import org.dromara.hutool.core.util.CharUtil;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 列表类型的服务加载器,用于替换JDK提供的{@link java.util.ServiceLoader}
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class ListServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
|
||||
private static final String PREFIX_SERVICES = "META-INF/services/";
|
||||
|
||||
// region ----- of
|
||||
|
||||
/**
|
||||
* 构建KVServiceLoader
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @param serviceClass 服务名称
|
||||
* @return KVServiceLoader
|
||||
*/
|
||||
public static <S> ListServiceLoader<S> of(final Class<S> serviceClass) {
|
||||
return of(serviceClass, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建KVServiceLoader
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @param serviceClass 服务名称
|
||||
* @param classLoader 自定义类加载器, {@code null}表示使用默认当前的类加载器
|
||||
* @return KVServiceLoader
|
||||
*/
|
||||
public static <S> ListServiceLoader<S> of(final Class<S> serviceClass, final ClassLoader classLoader) {
|
||||
return of(PREFIX_SERVICES, serviceClass, classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建KVServiceLoader
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @param pathPrefix 路径前缀
|
||||
* @param serviceClass 服务名称
|
||||
* @param classLoader 自定义类加载器, {@code null}表示使用默认当前的类加载器
|
||||
* @return KVServiceLoader
|
||||
*/
|
||||
public static <S> ListServiceLoader<S> of(final String pathPrefix, final Class<S> serviceClass,
|
||||
final ClassLoader classLoader) {
|
||||
return new ListServiceLoader<>(pathPrefix, serviceClass, classLoader, null);
|
||||
}
|
||||
// endregion
|
||||
|
||||
private final List<String> serviceNames;
|
||||
private final SimpleCache<String, S> serviceCache;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param pathPrefix 路径前缀
|
||||
* @param serviceClass 服务名称
|
||||
* @param classLoader 自定义类加载器, {@code null}表示使用默认当前的类加载器
|
||||
* @param charset 编码,默认UTF-8
|
||||
*/
|
||||
public ListServiceLoader(final String pathPrefix, final Class<S> serviceClass,
|
||||
final ClassLoader classLoader, final Charset charset) {
|
||||
super(pathPrefix, serviceClass, classLoader, charset);
|
||||
this.serviceNames = new ArrayList<>();
|
||||
this.serviceCache = new SimpleCache<>(new HashMap<>());
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
final MultiResource resources = ResourceUtil.getResources(
|
||||
pathPrefix + serviceClass.getName(),
|
||||
this.classLoader);
|
||||
for (final Resource resource : resources) {
|
||||
parse(resource);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.serviceNames.size();
|
||||
}
|
||||
|
||||
private void parse(final Resource resource){
|
||||
try(final BufferedReader reader = resource.getReader(this.charset)){
|
||||
int lc = 1;
|
||||
while(lc >= 0){
|
||||
lc = parseLine(resource, reader, lc, this.serviceNames);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private int parseLine(final Resource resource, final BufferedReader r, final int lc,
|
||||
final List<String> names)
|
||||
throws IOException {
|
||||
String ln = r.readLine();
|
||||
if (ln == null) {
|
||||
return -1;
|
||||
}
|
||||
final int ci = ln.indexOf('#');
|
||||
if (ci >= 0) ln = ln.substring(0, ci);
|
||||
ln = ln.trim();
|
||||
final int n = ln.length();
|
||||
if (n != 0) {
|
||||
if ((ln.indexOf(CharUtil.SPACE) >= 0) || (ln.indexOf(CharUtil.TAB) >= 0))
|
||||
fail(resource, lc, "Illegal configuration-file syntax");
|
||||
int cp = ln.codePointAt(0);
|
||||
if (!Character.isJavaIdentifierStart(cp))
|
||||
fail(resource, lc, "Illegal provider-class name: " + ln);
|
||||
for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
|
||||
cp = ln.codePointAt(i);
|
||||
if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
|
||||
fail(resource, lc, "Illegal provider-class name: " + ln);
|
||||
}
|
||||
if (!serviceCache.containsKey(ln) && !names.contains(ln))
|
||||
names.add(ln);
|
||||
}
|
||||
return lc + 1;
|
||||
}
|
||||
|
||||
private void fail(final Resource resource, final int line, final String msg) {
|
||||
throw new SPIException(this.serviceClass + ":" + resource.getUrl() + ":" + line + ": " + msg);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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:
|
||||
* http://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.spi;
|
||||
|
||||
import org.dromara.hutool.core.exceptions.ExceptionUtil;
|
||||
import org.dromara.hutool.core.text.StrUtil;
|
||||
|
||||
/**
|
||||
* SPI异常
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public class SPIException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SPIException(final Throwable cause) {
|
||||
super(ExceptionUtil.getMessage(cause), cause);
|
||||
}
|
||||
|
||||
public SPIException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SPIException(final String messageTemplate, final Object... params) {
|
||||
super(StrUtil.format(messageTemplate, params));
|
||||
}
|
||||
|
||||
public SPIException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SPIException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
public SPIException(final Throwable cause, final String messageTemplate, final Object... params) {
|
||||
super(StrUtil.format(messageTemplate, params), cause);
|
||||
}
|
||||
}
|
@ -20,4 +20,16 @@ package org.dromara.hutool.core.spi;
|
||||
* @author looly
|
||||
*/
|
||||
public interface ServiceLoader<T> {
|
||||
|
||||
/**
|
||||
* 加载服务
|
||||
*/
|
||||
void load();
|
||||
|
||||
/**
|
||||
* 服务总数
|
||||
*
|
||||
* @return 总数
|
||||
*/
|
||||
int size();
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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:
|
||||
* http://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.util;
|
||||
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* {@link AccessController}相关封装
|
||||
*
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class AccessUtil {
|
||||
|
||||
/**
|
||||
* @param action 执行内容
|
||||
* @param context 上下文,当为{@code null}时直接执行内容,而不检查
|
||||
* @param <T> 执行结果类型
|
||||
* @return 结果
|
||||
*/
|
||||
public static <T> T doPrivileged(final PrivilegedAction<T> action,
|
||||
final AccessControlContext context) {
|
||||
if (null == context) {
|
||||
return action.run();
|
||||
}
|
||||
|
||||
return AccessController.doPrivileged(action, context);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user