前言
SPI相信大家都听过,来看一下SPI的定义:
SPI(Service Provider Interface) 是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。 SPI的作用就是为这些被扩展的API寻找服务实现。
我们平时开发接触的比较频繁的SPI机制就是java的ServiceLoader(META-INF/services)与SpringBoot的SpringFactoriesLoader(META-INF/spring.factories),这次我们来介绍一下java的ServiceLoader的使用,并且用它来实现一个策略+工厂模式。
开始
创建接口
/**
* @author wyh
* @date 2021/6/3 14:32
*/
public interface MobilePhone {
String getName();
BrandEnum getBrand();
}
/**
* @author wyh
* @date 2021/6/3 16:29
*/
public enum BrandEnum {
APPLE,MI,HUAWEI
}
创建工厂类
/**
* 使用serviceLoader动态获取某个interface或abstract class的实现
* <p>
* 如不使用google的autoService{@link com.google.auto.service.AutoService},
* 则需要自己创建{@code META-INF/services/${your.service.path}}文件,
* 内容为${your.service.path}所有实现类的全限定名,
* 如果有多个实现需要换行<p>
*
* @author wyh
* @date 2021/6/3 16:31
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class PhoneFactory {
public static MobilePhone getByName(BrandEnum brand) {
if (brand != null) {
ServiceLoader<MobilePhone> serviceLoader = ServiceLoader.load(MobilePhone.class);
for (MobilePhone mobilePhone : serviceLoader) {
if (brand.equals(mobilePhone.getBrand())) {
return mobilePhone;
}
}
}
throw new UnknownTypeException();
}
}
使用
测试包下或客户端中创建各种实现类
/**
* @author wyh
* @date 2021/6/3 14:40
*/
@AutoService(MobilePhone.class)
public class IPhone implements MobilePhone {
@Override
public String getName() {
return "IPHONE7";
}
@Override
public BrandEnum getBrand() {
return BrandEnum.APPLE;
}
}
/**
* @author wyh
* @date 2021/6/3 14:41
*/
@AutoService(MobilePhone.class)
public class XiaoMi implements MobilePhone {
@Override
public String getName() {
return "MI9";
}
@Override
public BrandEnum getBrand() {
return BrandEnum.MI;
}
}
/**
* @author wyh
* @date 2021/6/3 16:38
*/
@AutoService(MobilePhone.class)
public class Huawei implements MobilePhone {
@Override
public String getName() {
return "MATE50";
}
@Override
public BrandEnum getBrand() {
return BrandEnum.HUAWEI;
}
}
这里为了方便使用了google提供的一个工具包提供的@AutoService注解,这样我们就无需去创建META-INF/services下的文件了(手动创建的规则详见工厂类的注释),编译期会自动帮我们生成
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
<version>${annotation-processor.version}</version>
</dependency>
获取实现
/**
* @author wyh
* @date 2021/6/3 14:45
*/
class ServiceLoaderTest {
@Test
void load() {
Assertions.assertNotNull(PhoneFactory.getByName(BrandEnum.APPLE));
Assertions.assertNotNull(PhoneFactory.getByName(BrandEnum.HUAWEI));
Assertions.assertNotNull(PhoneFactory.getByName(BrandEnum.MI));
}
}
打完收工:p