Dubbo 是阿里巴巴开源的一款高性能、轻量级分布式服务框架,基于 Java 的 RPC 协议,支持多种协议和多种注册中心。其官方网站为 https://dubbo.apache.org/zh/。
本文将从以下几个方面对 Dubbo 进行详细讲解:
Dubbo 实现思路主要是将服务提供者发布到注册中心,消费者通过相应的接口调用服务,并通过 Dubbo 进行远程调用。
Dubbo 的实现,可以按照下面几个层次进行划分,如下图所示[1]:
public interface HelloService {
String sayHello(String name);
}
<dubbo:application name="dubbo-demo-consumer" />
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<dubbo:reference id="helloService" interface="com.example.demo.service.HelloService" />
public class HelloServiceProxy implements HelloService {
private GenericService genericService;
public HelloServiceProxy(GenericService genericService) {
super();
this.genericService = genericService;
}
@Override
public String sayHello(String name) {
Object result = genericService.$invoke("sayHello", new String[]{String.class.getName()}, new Object[]{name});
return String.valueOf(result);
}
}
@Service(interfaceName = "com.example.demo.service.HelloService")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "Hello, " + name + "!";
}
}
<dubbo:service interface="com.example.demo.service.HelloService" ref="helloService">
<dubbo:cluster loadbalance="random" />
</dubbo:service>
<dubbo:service interface="com.example.demo.service.HelloService" ref="helloService">
<dubbo:monitor protocol="registry" />
</dubbo:service>
public class HelloServiceProtocol implements Protocol {
@Override
public int getDefaultPort() {
return 8080;
}
@Override
public Exporter export(Invoker invoker) throws RpcException {
return null;
}
@Override
public Invoker refer(Class type, URL url) throws RpcException {
if (GenericService.class.equals(type)) {
return new HelloServiceInvoker(type, url);
}
return null;
}
@Override
public void destroy() {
}
}
public class LogFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String serviceName = invoker.getInterface().getSimpleName();
String methodName = invocation.getMethodName();
long start = System.currentTimeMillis();
Result result = invoker.invoke(invocation);
long end = System.currentTimeMillis();
LOG.info("Invoke {}.{}, dataSize:{}, time:{}ms", serviceName, methodName, result.getData().length, end - start);
return result;
}
}
public class HelloServiceInvoker<T> extends AbstractInvoker<T> {
public HelloServiceInvoker(Class<T> type, URL url) {
super(type, url);
}
@Override
protected Result doInvoke(Invocation invocation) throws Throwable {
String methodName = invocation.getMethodName();
Object[] arguments = invocation.getArguments();
if ("sayHello".equals(methodName)) {
String name = (String) arguments[0];
String result = "Hello, " + name + "!";
return new RpcResult(result);
}
return new RpcResult();
}
}
// 在 resources/META-INF/dubbo/com.alibaba.dubbo.rpc.cluster.LoadBalance 文件中配置名称为 "random" 的 LoadBalance 实现类。
@SPI("random")
public interface LoadBalance {
/**
* Select one invoker in list.
* <p>
* 随机选择一个服务提供者调用。
* </p>
*
* @param invokers invokers.
* @param url refer url
* @param invocation invocation.
* @return selected invoker.
* @throws RpcException 当发生异常时抛出。
*/
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}
Dubbo 支持的协议包括:
<!-- 使用 dubbo 协议暴露服务 -->
<dubbo:protocol name="dubbo" port="12345" />
<!-- 使用 dubbo 协议引用服务 -->
<dubbo:reference interface="com.example.demo.service.HelloService" protocol="dubbo" />
xml复制代码<!-- 使用 hessian 协议暴露服务 -->
<dubbo:protocol name="hessian" port="8080" />
<!-- 使用 hessian 协议引用服务 -->
<dubbo:reference interface="com.example.demo.service.HelloService" protocol="hessian" />
xml复制代码<!-- 使用 http 协议暴露服务 -->
<dubbo:protocol name="http" port="8080" />
<!-- 使用 http 协议引用服务 -->
<dubbo:reference interface="com.example.demo.service.HelloService" protocol="http" />
<!-- 使用 webservice 协议暴露服务 -->
<dubbo:protocol name="webservice" port="8080" />
<!-- 使用 webservice 协议引用服务 -->
<dubbo:reference interface="com.example.demo.service.HelloService" protocol="webservice" />
Dubbo 支持 SPI(Service Provider Interface)机制来进行功能拓展,其实现方式主要包括以下三点:
ExtensionLoader<Filter> extensionLoader = ExtensionLoader.getExtensionLoader(Filter.class);
Filter filter = extensionLoader.getExtension("log");
Result result = filter.invoke(invoker, invocation);
@Adaptive("loadbalance")
public interface LoadBalance {
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}
@Configuration
public class DubboConfiguration {
@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("dubbo-demo-provider");
return applicationConfig;
}
@Bean
public ProtocolConfig protocolConfig() {
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName("dubbo");
protocolConfig.setPort(20880);
return protocolConfig;
}
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
return registryConfig;
}
}
Dubbo 服务发现的实现原理是基于注册中心实现的,具体来说,Dubbo 通过注册中心将提供者的服务地址信息注册到注册中心,消费者通过注册中心获取服务提供者的地址信息,再进行调用。
在 Dubbo 中,服务发现由类org.apache.dubbo.registry.RegistryService
定义,并且有三种方式进行实现:Zookeeper、Redis 和 Multicast。
其中,Zookeeper 是 Dubbo 默认的注册中心实现方式。在 Dubbo 中,服务的注册与发现是通过类org.apache.dubbo.registry.Registry
和org.apache.dubbo.registry.RegistryFactory
完成的。
下面是一个基于 Zookeeper 注册中心实现的服务发现示例代码:
// 配置服务注册中心地址
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://127.0.0.1:2181");
// 配置服务消费者
ReferenceConfig<HelloService> reference = new ReferenceConfig<>();
reference.setRegistry(registry);
reference.setInterface(HelloService.class);
reference.setVersion("1.0.0");
// 获取服务对象并调用方法
HelloService helloService = reference.get();
String result = helloService.sayHello("world");
在上面的示例中,首先通过RegistryConfig
配置服务注册中心的地址,然后通过ReferenceConfig
配置服务的消费者,包括注册中心的配置、服务接口、以及版本号等。最后获取服务对象后,就可以调用服务提供者的方法。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。