@Adaptive这个注解就是适配策略,我都是称呼为最佳适配子类,或者最佳适配类。就是找到最佳的子实现类的,其实就是默认的类。这个注解可以打在类上方,那么dubbo SPI机制通过接口获取实例类,就是获取到有@Adaptive注解的实现类。
接口:
package com.enjoy.service;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;
import java.rmi.RemoteException;
import java.util.Map;
/**
* SPI 全称为 Service Provider Interface,是一种服务发现机制,目标是为接口寻找实现类。
* Java SPI 的作法:
* 1.在类路径下META-INF/service下创建文件,名称为接口的全限定名。
* 2.将接口实现类的全限定名配置在文件中
* 3.服务启动时,将由服务加载器读取配置文件,并加载实现类。
*
* Dubbo SPI的作法:
* 1.Dubbo 增强原生的SPI机制来更好的满足拓展要求,其以键值对的方式对接口的实现进行配置管理。
* 2.Dubbo引入三个注解: SPI、Adaptive和Activate。
*
* 只有标注了SPI注解的接口,才是Dubbo的菜
*/
@SPI("b")
public interface InfoService {
Object sayHello(String name) ;
//@Adaptive
Object passInfo(String msg, URL url) ;
}
实现类 InfoServiceAImpl:
package com.enjoy.infoService.impl;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Activate;
import com.enjoy.service.InfoService;
public class InfoServiceAImpl implements InfoService {
@Override
public Object sayHello(String name) {
System.out.println(name+",你好,调通了A实现!");
return name+",你好,调通了A实现!";
}
@Override
public Object passInfo(String msg, URL url) {
System.out.println("恭喜你,调通了A实现");
return msg;
}
}
实现类InfoServiceBImpl
package com.enjoy.infoService.impl;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Activate;
import com.enjoy.service.InfoService;
public class InfoServiceBImpl implements InfoService {
@Override
public Object sayHello(String name) {
System.out.println(name+",你好,调通了B实现!");
return name+",你好,调通了B实现!";
}
@Override
public Object passInfo(String msg, URL url) {
System.out.println("恭喜你,调通了B实现");
return msg;
}
}
实现类InfoServiceCImpl
package com.enjoy.infoService.impl;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.enjoy.service.InfoService;
@Adaptive
public class InfoServiceCImpl implements InfoService {
@Override
public Object sayHello(String name) {
System.out.println(name+",你好,调通了C实现!");
return name+",你好,调通了C实现!";
}
@Override
public Object passInfo(String msg, URL url) {
System.out.println("恭喜你,调通了C实现");
return msg;
}
}
测试:
case1:类上有@Adaptive注解,那么调用这个接口的方法,就会调用@Adaptive注解类的方法
case 2: @Adaptive也可以在接口中打在具体的方法上,然后根据URL传递的key选择具体的实现类,很灵活
注释掉之前的实现类C:
测试:
需要说明的是 test://localhost/test?info.service=a. info.service就是接口名InfoService的驼峰,还需要用 . 将各个单词拆分。当然我们也可以直接在接口中,给@Adaptive定义个名称,然后URL也需要修改
接口定义:
测试case中URL也需要修改:
至此,@Adaptive的功能演示完毕。
源码分析
那么,它是如何做到这样的功能的呢? 还是看源码,加载 ExtensionLoader 的流程是一样的,不懂可以看上一篇深入了解Dubbo SPI 工作机制——@Activate (5)_chen_yao_kerr的博客-CSDN博客
下面全是debug的流程:
1:
2:
我们看到步骤3中得到一个String code,而这个code就是我们拼接出来的一个静态代理类,它负责根据URL中的key调用具体的业务实现类。下面我拷贝出来它拼写的类:
通过代码确认,我们可以知道实际上我们获取到的是静态代理类
而最后一步,就是调用静态代理类的拼接好了的业务方法,整个流程就走通了。
个人觉得,这种适配的方式可以动态的根据URL选择具体的实现类,很灵活。但是,老是需要在方法中定义URL,这样静态代理类才能够根据Dubbo的适配方式去选择具体的实现类,写起来有点累赘。