As an RPC framework, Dubbo defines a complete set of API interfaces, allowing us to develop Dubbo applications based on the native API. For specific examples of using the native API to develop lightweight RPC and microservices applications, see the examples in Tutorial - API Development Mode. Its applicable scenarios fall into two categories:
The current entry APIs primarily include Bootstrap
, ServiceConfig
, ReferenceConfig
, etc., which are used for Dubbo application development in different scenarios.
The DubboBootstrap instance represents a Dubbo application, serving as the startup entry point for the entire Dubbo application. Based on DubboBootstrap, we can set up protocol, service, registry, metrics, etc., to register services and connect to the registry, similar to adjusting application.yml or application.properties files in Spring Boot.
It is recommended to use DubboBootstrap.start() as a centralized startup entry for the application. However, for convenience in publishing certain services independently after the process has started, Dubbo also allows direct calls to ServiceConfig.export() or ReferenceConfig.refer() methods to publish services. In this case, Service/Reference will register to the default DubboBootstrap instance, effectively similar to calling DubboBootstrap.service(…).start().
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.ServiceConfig;
import com.xxx.DemoService;
import com.xxx.DemoServiceImpl;
public class DemoProvider {
public static void main(String[] args) {
ConfigCenterConfig configCenter = new ConfigCenterConfig();
configCenter.setAddress("zookeeper://127.0.0.1:2181");
// Provider protocol configuration
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(12345);
protocol.setThreads(200);
// Note: ServiceConfig is a heavy object, encapsulating the connection with the registry and opening the service port
// Provider service exposure configuration
ServiceConfig<DemoService> demoServiceConfig = new ServiceConfig<>();
demoServiceConfig.setInterface(DemoService.class);
demoServiceConfig.setRef(new DemoServiceImpl());
demoServiceConfig.setVersion("1.0.0");
// Second service configuration
ServiceConfig<FooService> fooServiceConfig = new ServiceConfig<>();
fooServiceConfig.setInterface(FooService.class);
fooServiceConfig.setRef(new FooServiceImpl());
fooServiceConfig.setVersion("1.0.0");
...
// Simplifying configuration assembly and controlling the startup process through DubboBootstrap
DubboBootstrap.getInstance()
.application("demo-provider") // Application configuration
.registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) // Registry configuration
.protocol(protocol) // Global default protocol configuration
.service(demoServiceConfig) // Add ServiceConfig
.service(fooServiceConfig)
.start() // Start Dubbo
.await(); // Suspend wait (prevent process exit)
}
}
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.ServiceConfig;
import com.xxx.DemoService;
import com.xxx.DemoServiceImpl;
public class DemoConsumer {
public static void main(String[] args) {
// Referencing remote service
ReferenceConfig<DemoService> demoServiceReference = new ReferenceConfig<DemoService>();
demoServiceReference.setInterface(DemoService.class);
demoServiceReference.setVersion("1.0.0");
ReferenceConfig<FooService> fooServiceReference = new ReferenceConfig<FooService>();
fooServiceReference.setInterface(FooService.class);
fooServiceReference.setVersion("1.0.0");
// Simplifying configuration assembly and controlling the startup process through DubboBootstrap
DubboBootstrap bootstrap = DubboBootstrap.getInstance();
bootstrap.application("demo-consumer") // Application configuration
.registry(new RegistryConfig("zookeeper://127.0.0.1:2181")) // Registry configuration
.reference(demoServiceReference) // Add ReferenceConfig
.reference(fooServiceReference)
.start(); // Start Dubbo
...
// Use demoService just like local bean
// Get remote service interface proxy through Interface, no need to rely on ReferenceConfig object
DemoService demoService = DubboBootstrap.getInstance().getCache().get(DemoService.class);
demoService.sayHello("Dubbo");
FooService fooService = fooServiceReference.get();
fooService.greeting("Dubbo");
}
}
Global basic configurations can be set in DubboBootstrap, including application configuration, protocol configuration, registry, configuration center, metadata center, module, monitoring, SSL, provider configuration, consumer configuration, etc.
// Registry
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://192.168.10.1:2181");
...
// Provider protocol configuration
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(12345);
protocol.setThreads(200);
...
// Configuration Center
ConfigCenterConfig configCenter = new ConfigCenterConfig();
configCenter.setAddress("zookeeper://192.168.10.2:2181");
...
// Metadata Center
MetadataReportConfig metadataReport = new MetadataReportConfig();
metadataReport.setAddress("zookeeper://192.168.10.3:2181");
...
// Metrics
MetricsConfig metrics = new MetricsConfig();
metrics.setProtocol("dubbo");
...
// SSL
SslConfig ssl = new SslConfig();
ssl.setServerKeyCertChainPath("/path/ssl/server-key-cert-chain");
ssl.setServerPrivateKeyPath("/path/ssl/server-private-key");
...
// Provider configuration (default configuration for ServiceConfig)
ProviderConfig provider = new ProviderConfig();
provider.setGroup("demo");
provider.setVersion("1.0.0");
...
// Consumer configuration (default configuration for ReferenceConfig)
ConsumerConfig consumer = new ConsumerConfig();
consumer.setGroup("demo");
consumer.setVersion("1.0.0");
consumer.setTimeout(2000);
...
DubboBootstrap.getInstance()
.application("demo-app")
.registry(registry)
.protocol(protocol)
.configCenter(configCenter)
.metadataReport(metadataReport)
.module(new ModuleConfig("module"))
.metrics(metrics)
.ssl(ssl)
.provider(provider)
.consumer(consumer)
...
.start();
...
// Method-level configuration
List<MethodConfig> methods = new ArrayList<MethodConfig>();
MethodConfig method = new MethodConfig();
method.setName("sayHello");
method.setTimeout(10000);
method.setRetries(0);
methods.add(method);
// Referencing remote service
ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>(); // This instance is heavy, encapsulating the connection to the registry and the connection to the provider, please cache it, otherwise it may cause memory and connection leaks
...
reference.setMethods(methods); // Set method-level configuration
...
...
// This instance is heavy, encapsulating the connection to the registry and the connection to the provider, please cache it, otherwise it may cause memory and connection leaks
ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>();
// For direct point-to-point connection, you can specify the target address using reference.setUrl(), and setting the URL will bypass the registry,
// where the protocol corresponds to provider.setProtocol()'s value, the port corresponds to provider.setPort()'s value,
// and the path corresponds to service.setPath()'s value. If the path is not set, the default path is the interface name.
reference.setUrl("dubbo://10.20.130.230:20880/com.xxx.DemoService");
...
Through ServiceConfig, you can publish services directly, registering the service interface to an in-memory list and the registry. This can be very useful for scenarios that require dynamic service publishing.
Note: For ordinary application development scenarios, we recommend using DubboBootstrap API.
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.ServiceConfig;
import com.xxx.DemoService;
import com.xxx.DemoServiceImpl;
public class DemoProvider {
public static void main(String[] args) {
// Service implementation
DemoService demoService = new DemoServiceImpl();
// Current application configuration
ApplicationConfig application = new ApplicationConfig();
application.setName("demo-provider");
// Connection to registry configuration
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://10.20.130.230:2181");
// Provider protocol configuration
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(12345);
protocol.setThreads(200);
// Note: ServiceConfig is a heavy object, encapsulating the connection to the registry and opening the service port
// Provider service exposure configuration
ServiceConfig<DemoService> service = new ServiceConfig<DemoService>(); // This instance is heavy, encapsulating the connection to the registry, please cache it, otherwise it may cause memory and connection leaks
service.setApplication(application);
service.setRegistry(registry); // Multiple registries can use setRegistries()
service.setProtocol(protocol); // Multiple protocols can use setProtocols()
service.setInterface(DemoService.class);
service.setRef(demoService);
service.setVersion("1.0.0");
// Expose and register the service
service.export();
// Suspend wait (prevent process exit)
System.in.read();
}
}
Through ReferenceConfig, you can reference remote services and subscribe to service interfaces from the registry. This can be very useful for scenarios that require dynamic service publishing.
Note: For ordinary application development, we recommend using DubboBootstrap API.
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ConsumerConfig;
import org.apache.dubbo.config.ReferenceConfig;
import com.xxx.DemoService;
public class DemoConsumer {
public static void main(String[] args) {
// Current application configuration
ApplicationConfig application = new ApplicationConfig();
application.setName("demo-consumer");
// Connection to registry configuration
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://10.20.130.230:2181");
// Note: ReferenceConfig is a heavy object, encapsulating the connection to the registry and the connection to the service provider
// Referencing remote service
ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>(); // This instance is heavy, encapsulating the connection to the registry and to the provider, please cache it, otherwise it may cause memory and connection leaks
reference.setApplication(application);
reference.setRegistry(registry); // Multiple registries can use setRegistries()
reference.setInterface(DemoService.class);
reference.setVersion("1.0.0");
// Use demoService just like local bean
// Note: This proxy object encapsulates all communication details and is relatively heavy, please cache for reuse
DemoService demoService = reference.get();
demoService.sayHello("Dubbo");
}
}
The background of multi-instance deployment originates from the large-scale application deployment scenario of Dubbo within Alibaba Group. The main problems encountered by Alibaba Group include:
The entire design of Dubbo multi-instances is configured according to a three-layer model: Framework layer, Application layer, and Module layer.
Based on this three-layer mechanism, we can isolate Dubbo according to certain rules:
To achieve Dubbo’s multi-instance implementation, the most significant change made to the Dubbo framework is modifying most of the logic for obtaining parameters from static variables. The most notable change is the URL object used for parameter transfer within Dubbo now carries the ScopeModel state, which corresponds to the specific data-bearing objects of the aforementioned three-layer model. For more implementation principles and design details about multi-instances, please refer to Source Architecture - Multi-instance Design and Implementation.
ServiceConfig<DemoService> service = new ServiceConfig<>();
service.setInterface(DemoService.class);
service.setRef(new DemoServiceImpl());
ReferenceConfig<DemoService> reference1 = new ReferenceConfig<>();
reference1.setInterface(DemoService.class);
ReferenceConfig<DemoService> reference2 = new ReferenceConfig<>();
reference2.setInterface(DemoService.class);
// Create a launcher (automatically create a new ApplicationModel)
DubboBootstrap bootstrap1 = DubboBootstrap.newInstance();
// Specify application name
bootstrap1.application(new ApplicationConfig("dubbo-demo-app-1"))
.registry(new RegistryConfig("nacos://localhost:8848"))
// Create a module
.newModule()
// Publish service within the module
.service(service)
.endModule()
// Create another module
.newModule()
// Subscribe to service within the module
.reference(reference1)
.endModule()
.start();
// Create another launcher (automatically create a new ApplicationModel)
DubboBootstrap bootstrap2 = DubboBootstrap.newInstance();
// Specify application name
bootstrap2.application(new ApplicationConfig("dubbo-demo-app-2"))
.registry(new RegistryConfig("nacos://localhost:8848"))
// Create a module
.newModule()
// Subscribe to service within the module
.reference(reference2)
.endModule()
.start();
// stub1 and stub2 are two independent subscriptions, completely isolated
// Subscribed stub
DemoService stub1 = reference1.get();
System.out.println(stub1.sayHello("Hello World!"));
// Subscribed stub
DemoService stub2 = reference2.get();
System.out.println(stub2.sayHello("Hello World!"));
bootstrap1.stop();
bootstrap2.stop();
This example exposes a service of DemoService, provided by the application dubbo-demo-app-1. Simultaneously, we created two subscriptions, one in the application dubbo-demo-app-1 and another in dubbo-demo-app-2, and then invoked the subscriptions to obtain the expected results.
It is worth noting that although the service information for both subscriptions is entirely consistent, after the multi-instance transformation, these two subscriptions are completely isolated for the consumer side, meaning that the latest version of Dubbo now supports creating multiple subscriptions by changing parameters in a way similar to tuples.