当前位置:首页>编程知识库>后端开发知识>面试官:dubbo为什么没有采用jdk的spi机制?
面试官:dubbo为什么没有采用jdk的spi机制?
阅读 1
2021-07-02

1,jdk中的spi机制

1.1 spi的设计目标

面向的对象的设计里,模块之间是基于接口编程,模块之间不对实现类进行硬编码。
一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。 为了实现在模块装配的时候,不在模块里面写死代码,这就需要一种服务发现机制。
java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到代码之外。 即SPI机制就是有一个接口,然后有几个实现类,代码运行的时候要确定运行哪个实现类,而这些实现类也是可插拔的。

1.2 spi的具体约定

当服务的提供者(provider),提供了一个接口多种实现时,一般会在jar包的META-INF/services/目录下,创建该接口的同名文件。该文件里面的内容就是该服务接口的具体实现类的名称。
而当外部加载这个模块的时候,就能通过该jarMETA-INF/services/里的配置文件得到具体的实现类名,并加载实例化,完成模块的装配。
下面举两个例子:
1,比如加载具体的sql驱动包比如mysqlmysql-connector-java-5.1.35.jar\META-INF\services\java.sql.Driver就是spi扩展点 oracle:ojdbc6-11.2.0.1.0.jar\META-INF\services\java.sql.Driver
2,比如加载Spring-webServletContainerInitializerspring-web-4.2.0.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer

1.3 jdk的实战例子

1,写一个接口Command
public interface Command {  
    public void execute();  
}  
2,分别写两个接口的实现类 TurnOnCommandTurnOffCommand
public class TurnOnCommand implements Command {
    public void execute() {  
        System.out.println("Trun on....");
    }  
}  

public class TurnOffCommand implements Command {
    public void execute() {  
        System.out.println("Trun off....");
    }  
}  
3,在项目的resources\\META-ING\\services目录下新建一个com.abc.spi.Commandspi配置文件,内容为接口的两个实现类
内容为:
com.abc.spi.TurnOnCommand
com.abc.spi.TurnOffCommand
4,编写测试类Test
public class Test {

   public static void main(String[] args) {
       // 加载jdk的spi接口Command.class
      ServiceLoader<Command> serviceLoader=ServiceLoader.load(Command.class);
      // 遍历加载的jdk的接口
        for(Command command:serviceLoader){
            command.execute();  
        }  
   }

}
下图为测试结果:

1.4,JDK的SPI机制的缺点

1JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源.
2JDKSPI机制没有IocAOP的支持,因此dubbo用了自己的spi机制:增加了对扩展点IoCAOP的支持,一个扩展点可以直接setter注入其它扩展点。

2,dubbo的spi的约定

2.1 dubbo的spi文件存放在哪里?

生成的dubbojar包下的dubbo-2.5.3.jar\META-INF\dubbo\internal目录下的文件全部是spi的扩展机制

2.2 dubbo的SPI有哪些约定

1spi 文件 存储路径 在 META-INF\dubbo\internal 目录下 并且文件名为接口的全路径名 就是=接口的包名 接口名,例如:dubbo-2.5.3.jar\META-INF\dubbo\internal\com.alibaba.dubbo.rpc.Protocol
2,每个spi 文件里面的格式定义为:扩展名=具体的类名 ,例如 registries=com.alibaba.dubbo.registry.RegistriesPageHandlerpages。推荐:250期面试题

3,如何扩展dubbo的spi

比如自己要扩展dubboProtocol,要经过以下步骤:
1,新建一个工程,在src/main/resources/META-INF/dubbo目录下新建一个文件比如org.apache.dubbo.rpc.Protocol,里面内容写一个:xxProtocal=com.abc.XxxProtocol
工程目录如下:
2,然后在这个工程里新建一个XxxProtocol类实现Protocol接口,并实现相关方法
XxxProtocal.java:
package com.xxx;

import org.apache.dubbo.rpc.Protocol;

public class XxxProtocol implements Protocol {
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        return new XxxExporter(invoker);
    }
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        return new XxxInvoker(type, url);
    }
}
XxxExporter.java
package com.xxx;
 
import org.apache.dubbo.rpc.support.AbstractExporter;
 
public class XxxExporter<T> extends AbstractExporter<T> {
    public XxxExporter(Invoker<T> invoker) throws RemotingException{
        super(invoker);
        // ...
    }
    public void unexport() {
        super.unexport();
        // ...
    }
}
XxxInvoker.java
package com.xxx;
 
import org.apache.dubbo.rpc.support.AbstractInvoker;
 
public class XxxInvoker<T> extends AbstractInvoker<T> {
    public XxxInvoker(Class<T> type, URL url) throws RemotingException{
        super(type, url);
    }
    protected abstract Object doInvoke(Invocation invocation) throws Throwable {
        // ...
    }
}
3,可以把这个工程打包成jar包,然后在自己的dubbo provider工程里依赖刚才的那个spijar包,并在spring配置文件中配置如下:
<dubbo:protocol name=”XxxProtocol” port=”20000” />



感谢阅读,希望对你有所帮助 :)
来源:juejin.cn/post/6844904045803470855


 
  END
 


 题外推荐
 
 

 十期推荐

 
  【281期】滴滴二面:try-catch-finally 和 return 是什么顺序执行的?
  

 
 
  【282期】面试官:你能说说 Nacos 的实现原理吗?
  

 
 
  【283期】熊大同学的面试回忆录(2.5年开发经验)
  

 
 
  【284期】共享锁、排他锁、互斥锁、悲观锁、乐观锁、行锁、表锁、页面锁、不可重复读、丢失修改、读脏数据
  

 
 
  【285期】Spring的@Transactional如何实现的(必考)
  

 
 
  【286期】面试时被问到Flutter/Dart的HashMap怎么办?
  

 
 
  【287期】ArrayList使用forEach遍历的时候删除元素会报错吗?
  

 
 
  【288期】面试官:什么是CAP 定理,为什么CAP不能同时被满足?
  

 
 
  【289期】面试官:说一下JVM常用垃圾回收器的特点、优劣势、使用场景和参数设置
  

 
 
  【290期】为什么不建议使用Java序列化?
 
 
  

 
? ~
以上数据来源于网络,如有侵权,请联系删除。
评论 (0)