怎样利用网站做推广/北京网站seo公司
目录
背景
1、jdk的spi
2、Spring的spi
2、Dubbo的spi
思考
背景
近来看Hasor、Dubbo等框架都说到微内核(Microkernel),想想jdk、srping、dubbo、hasor等都谈SPI,决定随笔记录下各个框架的spi,文章主要谈jdk、spring、dubbo的spi机制,出于目前的水平看来,spi就是一种偷懒方式,框架内都是针对接口编程,而实现自己可做可不做,谁做的好可以插进来就用就完了。
1、jdk的spi
jdk的spi先说说java.util.ServiceLoader这个类吧,先看看咋用的尝试下spi,
//定义服务提供接口
public interface JdkProvider {int calculate(int x,int y);
}
//第一个服务
public class JdkFirstProvider implements JdkProvider {public int calculate(int x, int y) {System.out.println("JdkFirstProvider给出 2(x+y)");return 2*(x+y);}
}
//第二个服务
public class JdkSecondProvider implements JdkProvider {public int calculate(int x, int y) {System.out.println("JdkSecondProvider给出 x+y");return x + y;}
}
//消费者
public class JdkFirstCustomer {public static void main(String[] args) {ServiceLoader<JdkProvider> jdkProviders = ServiceLoader.load(JdkProvider.class);jdkProviders.forEach(service-> System.out.println(service.calculate(3,8)));}
}
附上一个时序图
jdk的spi大致就是委托ClassLoader去按META-INF/services/(接口全类名)加载各个实现类,之后反射实例化实现类存到map中,并将实例返回客户端。
2、Spring的spi
尝试下spring的spi
//bean接口
public interface SpringProvider {String sayHello();
}
//接口实现1
public class SpringChineseProvider implements SpringProvider {@Overridepublic String sayHello() {return "SpringChineseProvider 大家好!";}
}
//接口实现2
public class SpringUSProvider implements SpringProvider {@Overridepublic String sayHello() {return "SpringUSProvider hello everyone";}
}
//客户端
public class SpringCustomer {public static void main(String[] args) {List<SpringProvider> factories = SpringFactoriesLoader.loadFactories(SpringProvider.class, null);factories.forEach(factory->{System.out.println(factory.sayHello());});}
}
详细说了jdk的spi这个就不细说了,也是通过ClassLoader去META-INF/spring.factories加载class,然后反射实例化返回,说说应用吧,像SpringBoot用这种方式去加载一些自动配置类,即引入xx-starter就能够自动向spring容器中注入许多配置好的组件。
2、Dubbo的spi
//注册工厂
public class DubboMultiRegistryFactory extends AbstractRegistryFactory {@Overrideprotected Registry createRegistry(URL url) {return new DubboMultiRegistry(url);}
}
//注册
public class DubboMultiRegistry extends MulticastRegistry {public DubboMultiRegistry(URL url) {super(url);System.out.println("自定义注册中心");}
}
//客户端
public class TestExtensionLoader {public static void main(String[] args) {ExtensionLoader<RegistryFactory> loader = ExtensionLoader.getExtensionLoader(RegistryFactory.class);RegistryFactory remote = loader.getExtension("multicast1");Registry multicast = remote.getRegistry(new URL("multicast1", "224.5.6.7", 1234));System.out.println(multicast);}
}
//文件全名 META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory
//文件内容 multicast1=com.zkr.learning.dubbo.ext.register.DubboMultiRegistryFactory
可以看到dubbo的spi主要通过ExtensionLoader实现,整个过程大致也是ClassLoader加载META-INF/dubbo下的文件得到class,取得class后反射实例化,不过在这里实例化后多个一步依赖注入的过程,而依赖注入交给了ExtensionFactory,ExtensionFactory做了几种实现其中就包括SpringExtensionFactory,那总结下来也就是1、根据不同Class类型,到指定位置获取class实例化;2、执行注入交给ExtensionFactory。
思考
好的框架都做了方便的扩展机制,spi只是其中一种方式,其它的还有诸如:BeanPostProcessor让开发者干预到bean的生命周期,ServletContainerInitializer、ServletContextInitializer、WebApplicationInitializer将ServletContext暴露出来,让开发者可以在web应用中对servlet做些额外操作,ConfigurableEnvironment关联MutablePropertySources让开发者实现环境的可动态配置,ChannelHandler、ChannelHandlerContext、ChannelPipeline让开发者对数据的读写能进行自定义的操作,当然还有一些其它的像Flowable的各种引擎配置器,这些都是一些接口,也是一种方式,针对接口编程,当然spi也是接口编程,只是它是找固定位置的文件,其它的可能是做一个循环链式处理,当然在这里也看到了jdk思想的强大,不管啥框架吧,都会借鉴jdk的思想,然后做一些额外的优化,比如上文的3种扩展机制,因此接下来还要好好看看javase、javaee的其它思想。