各种spi机制实现与使用
SPI机制认识
1.java SPI机制
java SPI机制(service provider interface) jdk内置的服务提供发现机制,可以启用框架扩展或替换组件,主要思想是将装配的控制权移到程序之外
通俗的讲就是:为某个接口自动找到实现类并初始化。
使用:
- 定义接口
- 编写实现类实现接口逻辑
- 在类路径下添加目录META-INF/services,并在其下添加以接口权限定类名为名字的文件,内容是实现类的全限定类型名
- 使用ServiceLoader.load(接口)
ServiceLoadercontents = ServiceLoader.load(Content.class);
Iteratoriterator = contents.iterator();
while (iterator.hasNext()) {
// 调用next()时会使用Class.forName()加载类
Content content = iterator.next();
String searchContent = content.searchContent();
System.out.println("searchContent = " + searchContent);
}
缺点:一次性加载所有的实现类,不能实现按需加载
2.spring的 SPI机制
spring会加载所有jar包下的META-INF/spring.factories文件下的所有自动配置类(xxAutoConfiguration),根据引入的starter,会对相应的类进行实例化,在实例化的过程中又会读取xxProperties类中的属性值,此属性值是在application.yml中进行配置的
使用
- 定义接口
- 编写实现类实现接口逻辑
- 在类路径下添加目录META-INF/spring.factories文件,文件内容key=val01,val02。key是接口权限定类名,val是实现类的全限定类型名
- 使用SpringFactoriesLoader.loadFactories(接口.class, 类加载器)
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
Listfactories = SpringFactoriesLoader.loadFactories(Content.class, contextClassLoader);
源码
public static <T> List<T> loadFactories(Class<T> factoryType, @Nullable ClassLoader classLoader) {
Assert.notNull(factoryType, "'factoryType' must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
// 读取配置内容
List<String> factoryImplementationNames = loadFactoryNames(factoryType, classLoaderToUse);
if (logger.isTraceEnabled()) {
logger.trace("Loaded [" + factoryType.getName() + "] names: " + factoryImplementationNames);
}
List<T> result = new ArrayList<>(factoryImplementationNames.size());
for (String factoryImplementationName : factoryImplementationNames) {
// Class.forName()实例化
result.add(instantiateFactory(factoryImplementationName, factoryType, classLoaderToUse));
}
AnnotationAwareOrderComparator.sort(result);
return result;
}
3.dubbo的spi机制
以apache不是alibaba的dubbo实现。使用过滤器为案例
- 使用一个类实现org.apache.dubbo.rpc.Filter中invoke方法,类上并标注@Activate注解
@Activate注解有group属性,order属性。
group属性表示当前spi扩展在什么时候起作用。CommonConstants.PROVIDER表示:作为服务器(生产者)、CommonConstants.CONSUMER表示客户端(消费者)
order表示被执行的顺序,数字越小优先级越高
代码如下
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
@Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER})
public class LogRecordSPI implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
try {
return invoker.invoke(invocation);
} catch (RpcException e) {
System.out.println("RpcException");
throw new RuntimeException(e);
} finally {
System.out.println("finally");
}
}
}
- 项目resources目录中创建目录META-INF/dubbo,并创建一个以org.apache.dubbo.rpc.Filter,内容是spi服务id=xxx.xx.xxx.LogRecordSPI,如下
logRecordSP=com.abucloud.spi.LogRecordSPI
参考:调用拦截扩展