spi 现在已有实现
- jdk 提供实现
- dubbo里的spi实现
一、jdk实现
- 配置
- 定义接口
- 定义实现类
- 配置资源文件 classpath下创建(META-INF/services/接口全面:META-INF/services/spring.design.mode.test4.spi.DogService)
- 调用方法
ServiceLoader<DogService> loaders = ServiceLoader.load(DogService.class); for (DogService d : loaders) { d.sleep(); }
- 测试结果
黑色dog。。。汪汪叫,不睡觉... 白色dog。。。呼呼大睡觉...
- 代码下载
https://files.cnblogs.com/files/z-test/spi-jdk.rar
二、dubbo 里的spi实现。
- 用法介绍
//得到一个自适应实现类,用@Adaptive 注解的类,没有就自动生产一个自适应类,可以根据调用方法的参数,动态获取处理类 ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); //得到默认的实现类 ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension(); //通过名字得到实现类。 ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("name"); //通过url里的 key对应的参数获取实现类。1.先加载默认的激活实现,2加载key对应的value里的值。 ExtensionLoader.getExtensionLoader(Protocol.class).getActivateExtension(url, key);
- 配置
- 文件位置
//加载顺序 DUBBO_INTERNAL_DIRECTORY,DUBBO_DIRECTORY,SERVICES_DIRECTORY //即用户可以覆盖调源码里的实现。 private static final String DUBBO_DIRECTORY = "META-INF/dubbo/"; private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/"; private static final String SERVICES_DIRECTORY = "META-INF/services/";
-
- 配置文件内容如下 (文件名:接口全名;内容是key=value:自定义名称:接口实现类全名)
- 注解解释
- @SPI("dubbo") 标记接口,提供一个默认的实现 一便于getDefaultExtension()得到默认实现类
- @Adaptive
- 1.出现在实现类上,.getAdaptiveExtension() 可以得到对应的实现类,
- 2.出现在 接口里的对应的方法上 强制要求对应的方法有URL参数,或者参数里包含URL对象。(否则执行报错)
- 实现类是com.alibaba.dubbo.rpc.Protocol 动态获取协议 根据url.getProtocol() == null ? "dubbo" : url.getProtocol() 获取协议名称,url参数protocol 为空时使用默认名称即@SPI("dubbo")中的名称
-
public int getDefaultPort() { throw new UnsupportedOperationException( "method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); } public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException { if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null"); if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null"); com.alibaba.dubbo.common.URL url = arg0.getUrl(); String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol()); if (extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader .getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName); return extension.export(arg0); }
- 接口对应方法中含有com.alibaba.dubbo.rpc.Invocation的根据 url.getMethodParameter(methodName, "cache", "lru");“cache“为参数名,lru 为@spi中指定的默认值
-
public com.alibaba.dubbo.cache.Cache getCache(com.alibaba.dubbo.common.URL arg0, com.alibaba.dubbo.rpc.Invocation arg1) { if (arg0 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg0; if (arg1 == null) throw new IllegalArgumentException("invocation == null"); String methodName = arg1.getMethodName(); String extName = url.getMethodParameter(methodName, "cache", "lru"); if (extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.cache.CacheFactory) name from url(" + url.toString() + ") use keys([cache])"); com.alibaba.dubbo.cache.CacheFactory extension = (com.alibaba.dubbo.cache.CacheFactory) ExtensionLoader .getExtensionLoader(com.alibaba.dubbo.cache.CacheFactory.class).getExtension(extName); return extension.getCache(arg0, arg1); }
- 其他的实现为url.getParameter("channel.handler", "all") 如果@Adaptive({Constants.DISPATCHER_KEY, "dispather", "channel.handler"}) url.getParameter("dispatcher",url.getParameter("dispather", url.getParameter("channel.handler", "all")));
-
public com.alibaba.dubbo.remoting.ChannelHandler dispatch(com.alibaba.dubbo.remoting.ChannelHandler arg0, com.alibaba.dubbo.common.URL arg1) { if (arg1 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg1; String extName = url.getParameter("dispatcher", url.getParameter("dispather", url.getParameter("channel.handler", "all"))); if (extName == null) throw new IllegalStateException( "Fail to get extension(com.alibaba.dubbo.remoting.Dispatcher) name from url(" + url.toString() + ") use keys([dispatcher, dispather, channel.handler])"); com.alibaba.dubbo.remoting.Dispatcher extension = (com.alibaba.dubbo.remoting.Dispatcher) ExtensionLoader .getExtensionLoader(com.alibaba.dubbo.remoting.Dispatcher.class).getExtension(extName); return extension.dispatch(arg0, arg1); }
- @Activate(group = {Constants.PROVIDER, Constants.CONSUMER}) 激活的类,适用于getActivateExtension(url, key) 1.先查找适配的@activie对应的类,2,查找url里key的对应的value所对应的类。
- 动态注入属性(查找set方法,根据set方法参数类型和变量名查找可用对象注入到 spi生产的对象里面。可以注入spi里的对象和springcontext里的对象)
在 接口类对应的配置文件里,有两个实现类,spi 和spring
@Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { private final List<ExtensionFactory> factories; public AdaptiveExtensionFactory() { ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class); List<ExtensionFactory> list = new ArrayList<ExtensionFactory>(); for (String name : loader.getSupportedExtensions()) { list.add(loader.getExtension(name)); } factories = Collections.unmodifiableList(list); } @Override public <T> T getExtension(Class<T> type, String name) { for (ExtensionFactory factory : factories) { T extension = factory.getExtension(type, name); if (extension != null) { return extension; } } return null; } }
spring 获取需要注入的对象
public class SpringExtensionFactory implements ExtensionFactory { private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>(); public static void addApplicationContext(ApplicationContext context) { contexts.add(context); } public static void removeApplicationContext(ApplicationContext context) { contexts.remove(context); } @Override @SuppressWarnings("unchecked") public <T> T getExtension(Class<T> type, String name) { for (ApplicationContext context : contexts) { if (context.containsBean(name)) { Object bean = context.getBean(name); if (type.isInstance(bean)) { return (T) bean; } } } return null; } }
spi
public class SpiExtensionFactory implements ExtensionFactory { @Override public <T> T getExtension(Class<T> type, String name) { if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type); if (!loader.getSupportedExtensions().isEmpty()) { return loader.getAdaptiveExtension(); } } return null; } }
大家可以看看源码,根据用法介绍里的方法,跟进看看。
原文地址:https://www.cnblogs.com/z-test/p/9321751.html
时间: 2024-11-05 19:03:46