mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-24 18:04:54 +08:00
add test
This commit is contained in:
parent
3b53230a38
commit
bc9d665036
@ -41,6 +41,16 @@ import java.util.List;
|
||||
* <li>提供更加灵活的服务加载机制,当选择加载指定服务时,其它服务无需加载。</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* 服务文件默认位于"META-INF/services/"下,文件名为服务接口类全名。内容类似于:
|
||||
* <pre>
|
||||
* # 我是注释
|
||||
* hutool.service.Service1
|
||||
* hutool.service.Service2
|
||||
* </pre>
|
||||
* <p>
|
||||
* 通过调用{@link #getService(int)}方法,传入序号,即可获取对应服务。
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
@ -145,7 +155,7 @@ public class ListServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
*/
|
||||
public S getService(final int index) {
|
||||
final String serviceClassName = this.serviceNames.get(index);
|
||||
if(null == serviceClassName){
|
||||
if (null == serviceClassName) {
|
||||
return null;
|
||||
}
|
||||
return getServiceByName(serviceClassName);
|
||||
@ -155,6 +165,7 @@ public class ListServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
public Iterator<S> iterator() {
|
||||
return new Iterator<S>() {
|
||||
private final Iterator<String> nameIter = serviceNames.iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return nameIter.hasNext();
|
||||
@ -275,7 +286,7 @@ public class ListServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
*/
|
||||
private S createService(final String serviceClassName) {
|
||||
return AccessUtil.doPrivileged(() ->
|
||||
ConstructorUtil.newInstance(ClassLoaderUtil.loadClass(serviceClassName)),
|
||||
ConstructorUtil.newInstance(ClassLoaderUtil.loadClass(serviceClassName)),
|
||||
this.acc);
|
||||
}
|
||||
|
||||
|
@ -20,16 +20,29 @@ import org.dromara.hutool.core.text.StrUtil;
|
||||
import org.dromara.hutool.core.util.AccessUtil;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 键值对服务加载器,使用{@link Properties}加载并存储服务
|
||||
* 键值对服务加载器,使用{@link Properties}加载并存储服务<br>
|
||||
* 服务文件默认位于"META-INF/hutool/"下,文件名为服务接口类全名。
|
||||
*
|
||||
* <p>
|
||||
* 内容类似于:
|
||||
* <pre>
|
||||
* # 我是注释
|
||||
* service1 = hutool.service.Service1
|
||||
* service2 = hutool.service.Service2
|
||||
* </pre>
|
||||
* <p>
|
||||
* 通过调用{@link #getService(String)}方法,传入等号前的名称,即可获取对应服务。
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @author looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class KVServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
public class MapServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
|
||||
private static final String PREFIX_HUTOOL = "META-INF/hutool/";
|
||||
|
||||
@ -42,7 +55,7 @@ public class KVServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
* @param serviceClass 服务名称
|
||||
* @return KVServiceLoader
|
||||
*/
|
||||
public static <S> KVServiceLoader<S> of(final Class<S> serviceClass) {
|
||||
public static <S> MapServiceLoader<S> of(final Class<S> serviceClass) {
|
||||
return of(serviceClass, null);
|
||||
}
|
||||
|
||||
@ -54,7 +67,7 @@ public class KVServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
* @param classLoader 自定义类加载器, {@code null}表示使用默认当前的类加载器
|
||||
* @return KVServiceLoader
|
||||
*/
|
||||
public static <S> KVServiceLoader<S> of(final Class<S> serviceClass, final ClassLoader classLoader) {
|
||||
public static <S> MapServiceLoader<S> of(final Class<S> serviceClass, final ClassLoader classLoader) {
|
||||
return of(PREFIX_HUTOOL, serviceClass, classLoader);
|
||||
}
|
||||
|
||||
@ -67,9 +80,9 @@ public class KVServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
* @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);
|
||||
public static <S> MapServiceLoader<S> of(final String pathPrefix, final Class<S> serviceClass,
|
||||
final ClassLoader classLoader) {
|
||||
return new MapServiceLoader<>(pathPrefix, serviceClass, classLoader, null);
|
||||
}
|
||||
// endregion
|
||||
|
||||
@ -85,8 +98,8 @@ public class KVServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
* @param classLoader 自定义类加载器, {@code null}表示使用默认当前的类加载器
|
||||
* @param charset 编码,默认UTF-8
|
||||
*/
|
||||
public KVServiceLoader(final String pathPrefix, final Class<S> serviceClass,
|
||||
final ClassLoader classLoader, final Charset charset) {
|
||||
public MapServiceLoader(final String pathPrefix, final Class<S> serviceClass,
|
||||
final ClassLoader classLoader, final Charset charset) {
|
||||
super(pathPrefix, serviceClass, classLoader, charset);
|
||||
|
||||
this.serviceCache = new SimpleCache<>(new HashMap<>());
|
||||
@ -141,6 +154,7 @@ public class KVServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
return new Iterator<S>() {
|
||||
private final Iterator<String> nameIter =
|
||||
serviceProperties.stringPropertyNames().iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return nameIter.hasNext();
|
||||
@ -154,6 +168,7 @@ public class KVServiceLoader<S> extends AbsServiceLoader<S> {
|
||||
}
|
||||
|
||||
// region ----- private methods
|
||||
|
||||
/**
|
||||
* 创建服务,无缓存
|
||||
*
|
@ -25,12 +25,23 @@ public class SpiUtil {
|
||||
/**
|
||||
* 加载第一个可用服务,如果用户定义了多个接口实现类,只获取第一个不报错的服务
|
||||
*
|
||||
* @param <T> 接口类型
|
||||
* @param <S> 服务类型
|
||||
* @param clazz 服务接口
|
||||
* @return 第一个服务接口实现对象,无实现返回{@code null}
|
||||
*/
|
||||
public static <T> T loadFirstAvailable(final Class<T> clazz) {
|
||||
final Iterator<T> iterator = loadList(clazz).iterator();
|
||||
public static <S> S loadFirstAvailable(final Class<S> clazz) {
|
||||
return loadFirstAvailable(loadList(clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载第一个可用服务,如果用户定义了多个接口实现类,只获取第一个不报错的服务
|
||||
*
|
||||
* @param <S> 服务类型
|
||||
* @param serviceLoader {@link ServiceLoader}
|
||||
* @return 第一个服务接口实现对象,无实现返回{@code null}
|
||||
*/
|
||||
public static <S> S loadFirstAvailable(final ServiceLoader<S> serviceLoader) {
|
||||
final Iterator<S> iterator = serviceLoader.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
try {
|
||||
return iterator.next();
|
||||
|
@ -11,6 +11,10 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* 服务提供接口SPI(Service Provider interface)机制相关封装
|
||||
* 服务提供接口SPI(Service Provider interface)机制相关封装,包括:
|
||||
* <ul>
|
||||
* <li>{@link org.dromara.hutool.core.spi.ListServiceLoader},提供列表形式的服务定义</li>
|
||||
* <li>{@link org.dromara.hutool.core.spi.MapServiceLoader},提供键值对形式的服务定义</li>
|
||||
* </ul>
|
||||
*/
|
||||
package org.dromara.hutool.core.spi;
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.UtilException;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SpiUtilTest {
|
||||
|
||||
@Test
|
||||
void loadFirstAvailableTest() {
|
||||
final MapServiceLoader<TestSPI1> serviceLoader = MapServiceLoader.of(TestSPI1.class);
|
||||
final TestSPI1 testSPI1 = SpiUtil.loadFirstAvailable(serviceLoader);
|
||||
Assertions.assertNotNull(testSPI1);
|
||||
Assertions.assertEquals("test service 1", testSPI1.doSth());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getServiceClassTest() {
|
||||
final MapServiceLoader<TestSPI1> serviceLoader = MapServiceLoader.of(TestSPI1.class);
|
||||
final Class<TestSPI1> service1 = serviceLoader.getServiceClass("service1");
|
||||
Assertions.assertEquals(TestService1.class, service1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getServiceClassNotExistTest() {
|
||||
final MapServiceLoader<TestSPI1> serviceLoader = MapServiceLoader.of(TestSPI1.class);
|
||||
Assertions.assertThrows(UtilException.class, ()->{
|
||||
serviceLoader.getServiceClass("service2");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void getServiceClassEmptyTest() {
|
||||
final MapServiceLoader<TestSPI1> serviceLoader = MapServiceLoader.of(TestSPI1.class);
|
||||
final Class<TestSPI1> serviceEmpty = serviceLoader.getServiceClass("serviceEmpty");
|
||||
Assertions.assertNull(serviceEmpty);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getServiceNotDefineTest() {
|
||||
final MapServiceLoader<TestSPI1> serviceLoader = MapServiceLoader.of(TestSPI1.class);
|
||||
final Class<TestSPI1> service1 = serviceLoader.getServiceClass("serviceNotDefine");
|
||||
Assertions.assertNull(service1);
|
||||
}
|
||||
|
||||
public interface TestSPI1{
|
||||
String doSth();
|
||||
}
|
||||
|
||||
public static class TestService1 implements TestSPI1{
|
||||
|
||||
@Override
|
||||
public String doSth() {
|
||||
return "test service 1";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
# 无服务
|
||||
serviceEmpty =
|
||||
# 正常服务
|
||||
service1 = org.dromara.hutool.core.spi.SpiUtilTest$TestService1
|
||||
# 此服务类未定义
|
||||
service2 = org.dromara.hutool.core.spi.SpiUtilTest$TestService2
|
Loading…
Reference in New Issue
Block a user