1 概述
本文提供了基于protocol层的一个客户端、服务端代码例子。
从dubbo 2.7的架构图上可以看到protocol层上在Remoting层之上的,个人理解Protocol层不在讨论客户端和服务端的概念了,开始讨论服务提供者和服务消费者的概念了。
参考上一篇dubbo源码实践-protocol层-invoker理解,本文理解起来应该不难。
2 例子
2.1 项目截图
ProtocolClientTest服务消费者(即客户端)、ProtocolServerTest服务提供者(即提供者)。业务服务IAlfService是接口、AlfService是实现类。
2.2 服务提供者
ProtocolServerTest代码
package org.example.dubbo.protocol;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ServiceRepository;
import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;
import org.apache.dubbo.rpc.proxy.jdk.JdkProxyFactory;
import org.example.test.protocol.AlfService;
import org.example.test.protocol.IAlfService;
import java.io.IOException;
/** 服务端代码, 2022/12/29. */
public class ProtocolServerTest {
public static void main(String[] args) throws IOException {
//Protocol 层的SPI
Protocol dubboProtocol = new DubboProtocol();
//业务服务
AlfService alfService = new AlfService();
//代理工厂
ProxyFactory jdkProxyFactory = new JdkProxyFactory();
//创建URL
URLBuilder urlBuilder = new URLBuilder();
urlBuilder.setHost("localhost");
urlBuilder.setPort(9999);
//指定调用的服务
urlBuilder.setPath("alf/haha");
// urlBuilder.addParameter("version", "1.0");
// urlBuilder.addParameter("group", "abc");
URL url = urlBuilder.build();
//获取本地Invoker, 该Invoker内部包装了alfService。
Invoker<IAlfService> invoker = jdkProxyFactory.getInvoker(alfService, IAlfService.class, url);
//暴露服务, 最后会在端口9999上启动dubbo服务端程序
Exporter<IAlfService> export = dubboProtocol.export(invoker);
//注册服务, 否则请求到服务端找不到IAlfService的实现
ServiceRepository repository = ApplicationModel.getServiceRepository();
repository.registerService("alf/haha", IAlfService.class);
System.in.read();
}
}
2.3 服务消费者
ProtocolClientTest代码
package org.example.dubbo.protocol;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.URLBuilder;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.ProxyFactory;
import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol;
import org.apache.dubbo.rpc.proxy.jdk.JdkProxyFactory;
import org.example.test.protocol.IAlfService;
import java.io.IOException;
/** 客户端代码, 2022/12/29. */
public class ProtocolClientTest {
public static void main(String[] args) throws IOException {
//Protocol 层的SPI
Protocol protocol = new DubboProtocol();
//代理层, 用来创建代理对象。客户端需要通过ProxyFactory获取远程Invoker的代理类
ProxyFactory proxyFactory = new JdkProxyFactory();
//创建URL
URLBuilder urlBuilder = new URLBuilder();
urlBuilder.setHost("localhost");
urlBuilder.setPort(9999);
//服务的名字
urlBuilder.setPath("alf/haha");
//配置客户端离开发送请求数据
urlBuilder.addParameter("sent", true);
// urlBuilder.addParameter("version", "1.0");
// urlBuilder.addParameter("group", "abc");
URL url = urlBuilder.build();
//创建远程调用的Invoker
Invoker<IAlfService> invoker = protocol.refer(IAlfService.class, url);
//创建IAlfService的代理类
IAlfService alfService = proxyFactory.getProxy(invoker);
String s = alfService.sayHolle("111");
System.out.println("返回结果: " + s);
System.in.read();
}
}
2.4 业务服务类
IAlfService接口
package org.example.test.protocol;
/** 业务服务类接口 */
public interface IAlfService {
String sayHolle(String hi);
}
AlfService类
package org.example.test.protocol;
/** 业务类 */
public class AlfService implements IAlfService{
@Override
public String sayHolle(String hi) {
System.out.println("AlfService call");
return "hi " + hi;
}
}
2.5 代码运行结果
1)先启动ProtocolServerTest类。可以看到启动和暴露服务成功。
2)启动ProtocolClientTest类。消费者调用alfService.sayHolle("111"),接收到返回是"hi 111"。
3 总结
细心的读者已经发现代码中还使用Proxy层的类,Protocal层+Proxy层已经实现了服务的发布与消费。
官方对Protocal层和Proxy层的解释:
在 RPC 中,Protocol 是核心层,也就是只要有 Protocol + Invoker + Exporter 就可以完成非透明的 RPC 调用,然后在 Invoker 的主过程上 Filter 拦截点。
Proxy 层封装了所有接口的透明化代理,而在其它层都以 Invoker 为中心,只有到了暴露给用户使用时,才用 Proxy 将 Invoker 转成接口,或将接口实现转成 Invoker,也就是去掉 Proxy 层 RPC 是可以 Run 的,只是不那么透明,不那么看起来像调本地服务一样调远程服务。
这里的透明指的应该是服务消费者IAlfService alfService = proxyFactory.getProxy(invoker);, 我们直接调用IAlfService接口发送请求,而不是调用invoker来发送请求。
4 遗留问题
服务端提供服务时,不加下面两条语句,请求到达服务端后是找不到对应的业务service(即AlfService)的实例的。含义还需要理解一下。
ServiceRepository repository = ApplicationModel.getServiceRepository();
repository.registerService("alf/haha", IAlfService.class);