源码
https://gitee.com/you-jianming/code/tree/master/src/main/java/spi
/**
* 描述:仿造shardingsphere的一个spi的实现
*
* @author Madison You
* @created 14:17
*/
public class ShardingSphereSpiDemo {
public static void main(String[] args) {
/*new出一个主键策略的实例,自动将spi进行注册,通过uuid类型,查找出对应的 ShardingKeyGenerator 实现类*/
ShardingKeyGenerator shardingKeyGenerator = new ShardingKeyGeneratorServiceLoader().newService("UUID", new Properties());
System.out.println(shardingKeyGenerator);
}
}
/**
* 描述:自定义一个spi加载类
*
* @author Madison You
* @created 14:40
*/
public final class ShardingKeyGeneratorServiceLoader extends TypeBasedSPIServiceLoader<ShardingKeyGenerator> {
static {
/*将自定义的接口注册进一个全局的spi加载集合*/
NewInstanceServiceLoader.register(ShardingKeyGenerator.class);
}
public ShardingKeyGeneratorServiceLoader() {
super(ShardingKeyGenerator.class);
}
}
/**
* 描述:spi注册类
*
* @author Madison You
* @created 14:27
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class NewInstanceServiceLoader {
private static final Map<Class, Collection<Class<?>>> SERVICE_MAP = new HashMap<>();
public static <T> void register(final Class<T> service) {
for (T each : ServiceLoader.load(service)) {
registerServiceClass(service, each);
}
}
/**
* 描述:注册方法,将spi注册进 SERVICE_MAP,以便于通过type进行加载
*
* @author Madison You
* @created 2022/4/23 15:05:00
* @param
* @return
*/
private static <T> void registerServiceClass(final Class<T> service, final T instance) {
Collection<Class<?>> serviceClasses = SERVICE_MAP.get(service);
if (null == serviceClasses) {
serviceClasses = new LinkedHashSet<>();
}
serviceClasses.add(instance.getClass());
SERVICE_MAP.put(service, serviceClasses);
}
@SneakyThrows
public static <T> Collection<T> newServiceInstances(final Class<T> service) {
Collection<T> result = new LinkedList<>();
if (null == SERVICE_MAP.get(service)) {
return result;
}
for (Class<?> each : SERVICE_MAP.get(service)) {
result.add((T) each.newInstance());
}
return result;
}
}
@RequiredArgsConstructor
public abstract class TypeBasedSPIServiceLoader<T extends TypeBasedSPI>{
private final Class<T> classType;
public final T newService(final String type, final Properties props) {
Collection<T> typeBasedServices = loadTypeBasedServices(type);
if (typeBasedServices.isEmpty()) {
throw new RuntimeException(String.format("Invalid `%s` SPI type `%s`.", classType.getName(), type));
}
T result = typeBasedServices.iterator().next();
result.setProperties(props);
return result;
}
public final T newService() {
T result = loadFirstTypeBasedService();
result.setProperties(new Properties());
return result;
}
private Collection<T> loadTypeBasedServices(String type) {
return Collections2.filter(NewInstanceServiceLoader.newServiceInstances(classType), input -> type.equalsIgnoreCase(input.getType()));
}
private T loadFirstTypeBasedService() {
Collection<T> instances = NewInstanceServiceLoader.newServiceInstances(classType);
if (instances.isEmpty()) {
throw new RuntimeException(String.format("Invalid `%s` SPI, no implementation class load from SPI.", classType.getName()));
}
return instances.iterator().next();
}
}
/**
* 描述:定义基础的spi类型接口
*
* @author Madison You
* @created 14:18
*/
public interface TypeBasedSPI {
/**
* 描述:获取类型
*
* @author Madison You
* @created 2022/4/23 14:19:00
* @param
* @return
*/
String getType();
/**
* 描述:获取配置
*
* @author Madison You
* @created 2022/4/23 14:20:00
* @param
* @return
*/
Properties getProperties();
/**
* 描述:设置配置属性
*
* @author Madison You
* @created 2022/4/23 14:20:00
* @param
* @return
*/
void setProperties(Properties properties);
}
/**
* 描述:定义一个主键生成的接口
*
* @author Madison You
* @created 14:35
*/
public interface ShardingKeyGenerator extends TypeBasedSPI {
Comparable<?> generateKey();
}
/**
* 描述:uuid主键生成接口
*
* @author Madison You
* @created 14:36
*/
@Getter
@Setter
public final class UUIDShardingKeyGenerator implements ShardingKeyGenerator {
private Properties properties = new Properties();
@Override
public String getType() {
return "UUID";
}
@Override
public synchronized Comparable<?> generateKey() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
}
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>